Skip to content
Back to skills

Rsa Common Modulus

ASecurity

Aynı N ile iki farklı e kullanılarak şifrelenmiş mesaj, extended GCD ile çözülür

  • 4 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 8, 2026
securitypythongogitapi

Works with

  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 8, 2026

npx -y skills add MustafaKemal0146/fetih --skill rsa-common-modulus --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Rsa Common Modulus?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Rsa Common Modulus
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mustafakemal0146-rsa-common-modulus/badge)](https://www.skillsdirectory.com/skills/mustafakemal0146-rsa-common-modulus)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: rsa-common-modulus
description: Aynı N ile iki farklı e kullanılarak şifrelenmiş mesaj, extended GCD ile çözülür
tags: [ctf, crypto, rsa, common-modulus, ortak-modul, extended-gcd, bezout]
triggers:
  - "aynı N iki farklı e"
  - "common modulus"
  - "ortak modül"
  - "two ciphertexts same n"
  - "e1 e2 coprime"
  - "gcd(e1,e2)=1"
difficulty: medium
category: crypto
solved_challenges:
  - "CryptoCTF 2021 - DoRSA (continued fraction variant)"
  - "CryptoHack - Everything is Big"
adapted_for: fetih
---

# RSA Common Modulus Saldırısı

## Ne Zaman Kullan

Aşağıdaki koşullar sağlanıyorsa bu tekniği dene:

- Aynı `N` (modulus) kullanılmış, **farklı** `e1` ve `e2` ile
- Aynı mesaj `m` her iki anahtarla şifrelenmiş:
  ```
  c1 = m^e1 mod N
  c2 = m^e2 mod N
  ```
- `gcd(e1, e2) == 1` (coprime — birbirlerine göre asallar)

**Nereden anlarsın?**
- Challenge iki farklı public key veriyor ama N aynı
- Kaynak kodda `n = p * q` bir kez üretiliyor, e farklı seçiliyor
- "Bob her mesajı iki farklı alıcıya gönderdi" senaryosu

**Bu teknik çalışmaz eğer:**
- `gcd(e1, e2) > 1` — bu durumda farklı yaklaşım gerekir (aşağıda açıklandı)
- Mesajlar farklı (`m1 ≠ m2`) — şifreleme farklı plaintext üzerinde yapılmış

---

## Matematiksel Temel

### Bezout Lemması

İki tamsayı `a` ve `b` için `gcd(a, b) = 1` ise, şunu sağlayan `x` ve `y` tam sayıları vardır:

```
a*x + b*y = 1
```

### Saldırının Mantığı

Bezout lemmasını `e1` ve `e2` için uygula:

```
e1*a + e2*b = 1        (a, b < 0 veya > 0 olabilir)
```

Extended GCD algoritması bunu bulur. Sonra:

```
c1^a * c2^b mod N
= (m^e1)^a * (m^e2)^b mod N
= m^(e1*a) * m^(e2*b) mod N
= m^(e1*a + e2*b) mod N
= m^1 mod N
= m
```

Negatif üsler için modüler ters gerekir:
```
c^(-k) mod N  ≡  modinv(c, N)^k mod N
```

---

## Tam Python Exploit Kodu

```python
#!/usr/bin/env python3
"""
RSA Common Modulus Saldirisi
Ayni N, farkli e1 ve e2 ile sifrelenip gcd(e1,e2)=1 ise calısır.

Gereksinimler: pycryptodome
  pip install pycryptodome
"""

import math
from Crypto.Util.number import long_to_bytes


def extended_gcd(a: int, b: int):
    """
    Genisletilmis Oklid algoritmasi.
    Dondurur: (g, x, y) oyle ki a*x + b*y = g = gcd(a, b)
    """
    if a == 0:
        return b, 0, 1
    g, x, y = extended_gcd(b % a, a)
    return g, y - (b // a) * x, x


def modinv(a: int, m: int) -> int:
    """a'nin m modülundeki tersi. gcd(a,m)=1 olmali."""
    g, x, _ = extended_gcd(a % m, m)
    if g != 1:
        raise ValueError(f"Modüler ters yok: gcd({a},{m}) = {g}")
    return x % m


def common_modulus_attack(n: int, e1: int, e2: int, c1: int, c2: int) -> bytes:
    """
    RSA Common Modulus saldırısı.

    Parametreler:
        n  : Ortak modulus
        e1 : Birinci public exponent
        e2 : Ikinci public exponent
        c1 : c1 = m^e1 mod n
        c2 : c2 = m^e2 mod n

    Dondurur: plaintext (bytes)
    """
    # On kontrol
    g = math.gcd(e1, e2)
    if g != 1:
        print(f"[!] UYARI: gcd(e1, e2) = {g}, saldiri dogrudan calismayabilir.")
        print(f"    e1 = {e1}, e2 = {e2}")
        print(f"    Fallback: e1,e2'yi {g}'ye bol ve dene.")
        # Fallback: ortak boleni at
        e1_r, e2_r = e1 // g, e2 // g
        return common_modulus_attack(n, e1_r, e2_r, c1, c2)

    # Bezout katsayılarını bul: e1*a + e2*b = 1
    gcd_val, a, b = extended_gcd(e1, e2)
    print(f"[*] e1*a + e2*b = 1 cozumu:")
    print(f"    a = {a}")
    print(f"    b = {b}")
    print(f"    Dogrulama: {e1}*{a} + {e2}*{b} = {e1*a + e2*b}")

    # Negatif usler icin modüler ters kullan
    if a < 0:
        # c1^a mod n = modinv(c1, n)^(-a) mod n
        c1_part = pow(modinv(c1, n), -a, n)
    else:
        c1_part = pow(c1, a, n)

    if b < 0:
        c2_part = pow(modinv(c2, n), -b, n)
    else:
        c2_part = pow(c2, b, n)

    # m = c1^a * c2^b mod n
    m = (c1_part * c2_part) % n
    print(f"[+] Mesaj (int): {m}")

    result = long_to_bytes(m)
    print(f"[+] Mesaj (bytes): {result}")
    return result


# =========================================================
# CHALLENGE DEGERLERİNİ BURAYA KOY
# =========================================================
if __name__ == "__main__":
    # Ornek — gercek challenge degerlerini buraya yapistir:
    n  = 0xDEADBEEFCAFEBABE   # Ortak modulus
    e1 = 17                    # Birinci exponent
    e2 = 65537                 # Ikinci exponent
    c1 = 0xAAAA                # Birinci sifreli metin
    c2 = 0xBBBB                # Ikinci sifreli metin

    flag = common_modulus_attack(n, e1, e2, c1, c2)
    print(f"\n[!!!] FLAG: {flag.decode(errors='replace')}")
```

---

## CryptoCTF 2021 — DoRSA Detaylı Örneği

**Challenge Açıklaması:**
"RSA with a twist. The twist is continued fractions."

**Verilen:**
```
n  = [büyük sayı]
e1 = [büyük sayı — n'ye yakın]
e2 = [büyük sayı — n'ye yakın]
c1 = m^e1 mod n
c2 = m^e2 mod n
```

**Özellik:** `e1` ve `e2` çok büyük — neredeyse `n` kadar. Bu durumda standart common modulus
saldırısı çalışır ama Bezout katsayıları `a` ve `b` astronomik büyür.

**CryptoCTF varyantında ek zorluk:** Challenge adında "DoRSA" ve continued fraction ipucu
verilmiş. Aslında `e1 * e2 ≈ n` ve `d ≈ sqrt(N)` gibi ilişkiler kurulabiliyor.

```python
# CryptoCTF DoRSA - genellestirilmis cozum cercevesi
from math import gcd, isqrt
from Crypto.Util.number import long_to_bytes

def solve_dorsa(n, e1, e2, c1, c2):
    """
    DoRSA tarzı challenge için ortak modulus + fallback yaklaşımı.
    """

    # Adim 1: gcd(e1, e2) kontrol
    g = gcd(e1, e2)
    print(f"[*] gcd(e1, e2) = {g}")

    if g == 1:
        # Klasik common modulus yeterli
        return common_modulus_attack(n, e1, e2, c1, c2)

    # Adim 2: gcd > 1 durumu — ortak faktoru indir
    # e1/g ve e2/g hala coprime mi?
    e1r, e2r = e1 // g, e2 // g
    g2 = gcd(e1r, e2r)
    print(f"[*] Indirgenmis: e1/g = {e1r}, e2/g = {e2r}, gcd = {g2}")

    if g2 == 1:
        # m^g'yi bul, sonra g. koku al
        m_g = common_modulus_attack(n, e1r, e2r, c1, c2)
        m_g_int = int.from_bytes(m_g, 'big')
        print(f"[*] m^{g} bulundu: {m_g_int}")

        # g. kok (tam sayi), ozellikle g=2 veya 3 ise makul
        m_candidate, is_perfect = gmpy2_iroot(m_g_int, g)
        if is_perfect:
            return long_to_bytes(m_candidate)
        else:
            print(f"[-] {g}. kök tam sayi degil — başka yaklasım lazim")
            return None

    print("[-] Indirgenmiş exponentler de coprime degil. Daha karmasik durum.")
    return None


def gmpy2_iroot(n, k):
    """gmpy2 olmadan tam kök kontrolü (küçük k için)."""
    try:
        import gmpy2
        return gmpy2.iroot(n, k)
    except ImportError:
        # Basit Newton yöntemi
        if k == 2:
            r = isqrt(n)
            return r, r * r == n
        # Genel Newton
        r = int(n ** (1/k))
        for candidate in [r-1, r, r+1]:
            if candidate ** k == n:
                return candidate, True
        return r, False
```

---

## Tuzaklar

### 1. `gcd(e1, e2) > 1` Durumu

En sık karşılaşılan zorluk. Örnek:

```
e1 = 6,  e2 = 10  →  gcd = 2

Bezout: 6a + 10b = 2  →  3a + 5b = 1
Cozum: a = 2, b = -1
Yani: 6*2 + 10*(-1) = 2

Elde edilen:  c1^2 * c2^(-1) mod n = m^2
Sonra: m = integer_sqrt(m^2)  — sadece m küçükse veya tam kare ise calısır
```

**Ne yapılır:**
- `m^g` elde edilir
- `g`'nin tam kökü alınır (`gmpy2.iroot`)
- Kök tam değilse: `m` modüler kareköke bakılır (`Tonelli-Shanks`)
- Hala olmuyorsa: başka teknik gerekir

### 2. Bezout Katsayıları Astronomik Büyük

`e1` ve `e2` büyük olduğunda `a` ve `b` çok büyür. Hesaplama yine de doğru çalışır
çünkü `pow(c, a, n)` Python'da verimli (modüler üs alma).

### 3. `modinv(c1, n)` Çalışmıyor

`gcd(c1, n) > 1` ise `c1` ve `n` ortak bir çarpana sahip — bu durumda:
```python
g = gcd(c1, n)
if g > 1:
    p = g          # n'nin bir asal çarpanı bulundu!
    q = n // p
    # RSA private key hesapla...
```
Bu aslında büyük bir hediyedir — N direkt çözüldü.

### 4. Şifreli Metin Hex mi Decimal mi?

```python
# Otomatik parse:
def parse_int(s):
    s = s.strip()
    if s.startswith("0x") or s.startswith("0X"):
        return int(s, 16)
    # Hex mi kontrol et (sadece 0-9, a-f)
    try:
        v = int(s, 16)
        # Eger buyuk buyuk int, hex olabilir
        if len(s) > 15:
            return v
    except ValueError:
        pass
    return int(s)
```

### 5. Sonuç Anlamsız Görünüyorsa

- `long_to_bytes(m)` yerine `long_to_bytes(m).strip(b'\x00')` dene
- Flag formatını kontrol et: `picoCTF{`, `flag{`, vb.
- `m` yanlış seçilmiş olabilir — `n - m` dene (negatif sonuç durumu)
- Mesaj UTF-8 değil başka encoding olabilir: `errors='replace'`

---

## Hızlı Kontrol Listesi

```
[ ] n1 == n2 mi? (ortak modulus var mı?)
[ ] gcd(e1, e2) == 1 mi? (coprime)
[ ] c1 ve c2 aynı mesaj için mi şifrelenmiş?
[ ] extended_gcd(e1, e2) → (1, a, b) bul
[ ] a < 0 ise modinv(c1, n)^|a| kullan
[ ] b < 0 ise modinv(c2, n)^|b| kullan
[ ] m = (c1^a * c2^b) % n
[ ] long_to_bytes(m) ile decode et
```

---

## Hızlı Tek Satır Çözüm

```python
from math import gcd
from Crypto.Util.number import long_to_bytes

def quick_common_modulus(n, e1, e2, c1, c2):
    from sympy import gcdex
    a, b, _ = gcdex(e1, e2)  # e1*a + e2*b = 1
    a, b = int(a), int(b)
    inv_c1 = pow(c1, -1, n)
    inv_c2 = pow(c2, -1, n)
    p1 = pow(c1, a, n) if a >= 0 else pow(inv_c1, -a, n)
    p2 = pow(c2, b, n) if b >= 0 else pow(inv_c2, -b, n)
    return long_to_bytes((p1 * p2) % n)

# Kullanim:
# flag = quick_common_modulus(n, e1, e2, c1, c2)
# print(flag.decode())
```

<!--
  ⚔ Bu skill FETIH AI Agent icin gelistirilmistir — https://github.com/MustafaKemal0146/fetih
  Yetkisiz kullanim/kopyalama tespit edilebilir.
  hash: d49661272a2194a5
-->

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…