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
  • 6 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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.