[πŸ₯‰ Bronze 2] κ±°λ“­μ œκ³± 차이 ν•œ μ€„λ‘œ 평문을 λ˜λŒλ¦¬λ‹€ β€” DreamHack ICM2022 풀이

2026-07-14Β·1λΆ„ 읽기·

[πŸ₯‰ Bronze 2] κ±°λ“­μ œκ³± 차이 ν•œ μ€„λ‘œ 평문을 λ˜λŒλ¦¬λ‹€ β€” DreamHack ICM2022 풀이

평문을 두 ν‚€μ˜ κ±°λ“­μ œκ³± 차이에 κ³±ν•΄ μ•”ν˜Έλ¬Έ ν•˜λ‚˜λ‘œ λ‚΄λ³΄λ‚΄λŠ” crypto 문제. ν‚€κ°€ 두 κ°œμ§€λ§Œ ν•˜λ‚˜λŠ” 곡개되고 λ‹€λ₯Έ ν•˜λ‚˜λŠ” 쒁은 λ²”μœ„λΌ, μ•”ν˜Έλ¬Έμ΄ μ •μˆ˜λ‘œ λ–¨μ–΄μ§€λŠ” ν‚€λ₯Ό μ „μˆ˜μ‘°μ‚¬ν•˜λ©΄ 평문 μ •μˆ˜ pκ°€ κ·ΈλŒ€λ‘œ λ³΅μ›λœλ‹€. κ·Έ p μžμ²΄κ°€ ν”Œλž˜κ·Έμ΄λ©°, ord 값을 이어 뢙인 ν˜•νƒœλΌ μ‚¬λžŒμ΄ 읽을 μˆ˜λ„ μžˆλ‹€.

문제: DreamHack β€” ICM2022 λΆ„λ₯˜: Crypto λ‚œμ΄λ„: πŸ₯‰ Bronze 2 FLAG: DH{10112210997116104}

μ•”ν˜Έλ¬Έ λ”± ν•˜λ‚˜(q)와 곡개된 νŒŒλΌλ―Έν„° μΌλΆ€λ§Œ μ£Όκ³  평문을 λ³΅μ›ν•˜λΌλŠ” λ¬Έμ œλ‹€. 겉보기엔 두 개의 ν‚€κ°€ μ–½νžŒ λ³΅μž‘ν•œ μ‹μ΄μ§€λ§Œ, μ‹€μ œλ‘œ 비밀은 ν‚€ ν•˜λ‚˜μ˜ 쒁은 λ²”μœ„λΏμ΄λ‹€. μ •μˆ˜λΌλŠ” μ œμ•½ ν•˜λ‚˜κ°€ κ·Έ λ²”μœ„λ₯Ό μ •λ‹΅ ν•˜λ‚˜λ‘œ μ’ν˜€ μ€€λ‹€.

μ•”ν˜Έλ¬Έ q ν•˜λ‚˜λ‘œ 평문 p λ₯Ό λ˜λŒλ¦¬λŠ” 흐름 β€” key1 을 μ „μˆ˜μ‘°μ‚¬ν•΄ μ •μˆ˜ p λ₯Ό 볡원
μ•”ν˜Έλ¬Έ q ν•˜λ‚˜λ‘œ 평문 p λ₯Ό λ˜λŒλ¦¬λŠ” 흐름 β€” key1 을 μ „μˆ˜μ‘°μ‚¬ν•΄ μ •μˆ˜ p λ₯Ό 볡원


문제 κ°œμš”

ν•­λͺ©λ‚΄μš©
문제λͺ…ICM2022
λ‚œμ΄λ„πŸ₯‰ Bronze 2
λΆ„λ₯˜Crypto
제곡 파일main.py, readme.txt
μŠ€νƒPython 3 (fractions.Fraction)
핡심 취약점킀 곡간이 쒁고 μ •μˆ˜ μ œμ•½μ΄ κ°•ν•΄ μ „μˆ˜μ‘°μ‚¬λ‘œ 평문 볡원

readme.txtκ°€ 절반쯀 곡개된 νŒŒλΌλ―Έν„°λ₯Ό μ•Œλ € μ£Όκ³ , "λ³΅ν˜Έν•œ pλ₯Ό DH{μ—¬κΈ°}에 λ„£μœΌλΌ"κ³  μ•ˆλ‚΄ν•œλ‹€. 즉 μš°λ¦¬κ°€ ꡬ할 건 평문 μ •μˆ˜ p κ·Έ μžμ²΄λ‹€.



🧩 λ°°κ²½ β€” κ±°λ“­μ œκ³±μ˜ 차이에 평문을 μ‹€μ—ˆλ‹€

μ•”ν˜Έν™” ν•¨μˆ˜λŠ” 평문 pλ₯Ό 두 ν‚€μ˜ κ±°λ“­μ œκ³± 차이에 κ³±ν•΄ ν•˜λ‚˜μ˜ 유리수 q둜 λ§Œλ“ λ‹€.

def enc(p, n, key1, key2):
    q = (Fraction(p, n+1) * key1**(n+1)) - (Fraction(p, n+1) * key2**(n+1))
    return q

Fraction(p, n+1)을 κ³΅ν†΅μœΌλ‘œ 묢으면 식이 λ‹¨μˆœν•΄μ§„λ‹€.

q = (p / (n+1)) Β· ( key1^(n+1) βˆ’ key2^(n+1) )

n, key1, key2κ°€ λͺ¨λ‘ μƒμˆ˜λΌλ©΄ qλŠ” p에 μ–΄λ–€ μ •ν•΄μ§„ 유리수λ₯Ό κ³±ν•œ 값일 뿐이닀. κ·Έ κ³±ν•˜λŠ” μƒμˆ˜λ§Œ μ•Œλ©΄ λ‚˜λˆ—μ…ˆ ν•œ 번으둜 pκ°€ λŒμ•„μ˜¨λ‹€. 이 문제의 μ „λΆ€λŠ” "κ·Έ μƒμˆ˜, 특히 key1을 μ–΄λ–»κ²Œ νŠΉμ •ν•˜λŠλƒ"λ‹€.


πŸ”¬ μ½”λ“œ μ •μ°° β€” 무엇이 κ³΅κ°œλλ‚˜

readme.txtκ°€ μ•Œλ € μ£ΌλŠ” 값은 이렇닀.

n = 3
key1 = #cencored#
key2 = 95
q = -200640142664324295933714
p = #cencored# (p is number)

n = 3μ΄λ‹ˆ n+1 = 4λ‹€. key2 = 95λŠ” 곡개, q도 곡개, 그런데 key1κ³Ό pλŠ” κ°€λ €μ Έ μžˆλ‹€. ν‚€ 생성 μ½”λ“œλ₯Ό 보면 key1의 λ²”μœ„μ— 결정적 νžŒνŠΈκ°€ μžˆλ‹€.

def key_make():
    n, key1, key2 = 0, 1, 0
    while key2 < key1:            # key2 < key1 인 λ™μ•ˆ 계속 λ‹€μ‹œ λ½‘μŒ
        n = random.randrange(1, 10)
        key1 = random.randrange(1, 100)
        key2 = random.randrange(1, 100)
    return n, key1, key2

while key2 < key1은 쑰건이 참인 λ™μ•ˆ λ°˜λ³΅ν•˜λ―€λ‘œ, 루프λ₯Ό λΉ μ Έλ‚˜μ˜€λŠ” μˆœκ°„μ—” key2 >= key1 이닀. 즉 key1 <= key2 = 95. κ²Œλ‹€κ°€ μ£Όμ–΄μ§„ qκ°€ μŒμˆ˜λΌλŠ” 사싀이 λ²”μœ„λ₯Ό 더 μ’νžŒλ‹€. q = (p/4)(key1^4 βˆ’ 95^4)μ—μ„œ pλŠ” μ–‘μˆ˜(λ¬Έμžλ“€μ˜ ordλ₯Ό 이어 뢙인 수)μ΄λ‹ˆ, qκ°€ 음수이렀면 key1^4 βˆ’ 95^4 < 0, κ³§ key1 < 95 μ—¬μ•Ό ν•œλ‹€. ν›„λ³΄λŠ” κ³ μž‘ 1..94λ‹€.


🧱 λ°°κ²½ β€” 평문 pλŠ” ASCII μ½”λ“œλ₯Ό 이어 뢙인 수

main.pyλŠ” μž…λ ₯ λ¬Έμžμ—΄μ„ μ΄λ ‡κ²Œ 숫자둜 λ°”κΎΌλ‹€.

p = ""
for character in emp:
    p += str(ord(character))     # 각 κΈ€μžμ˜ ord λ₯Ό λ¬Έμžμ—΄λ‘œ 이어 λΆ™μž„

ord('e') = 101, ord('z') = 122 … 이런 값을 κ·ΈλŒ€λ‘œ λ¬Έμžμ—΄λ‘œ λΆ™μ—¬ ν•˜λ‚˜μ˜ 큰 μ •μˆ˜λ‘œ λ§Œλ“ λ‹€. κ·Έλž˜μ„œ λ³΅μ›ν•œ pλ₯Ό 두세 μžλ¦¬μ”© λŠμ–΄ chr둜 되돌리면 원문이 λ‚˜μ˜¨λ‹€. μ•„λž˜λŠ” ASCII μ½”λ“œν‘œλ‘œ, μš°λ¦¬κ°€ 볡원할 μˆ«μžλ“€μ΄ μ–΄λ–€ λ¬Έμžμ— λŒ€μ‘ν•˜λŠ”μ§€ 보여 μ€€λ‹€.

ASCII μ½”λ“œν‘œ β€” 각 λ¬ΈμžλŠ” 32~126 λ²”μœ„μ˜ μ‹­μ§„ μ½”λ“œμ— λŒ€μ‘ν•œλ‹€
ASCII μ½”λ“œν‘œ β€” 각 λ¬ΈμžλŠ” 32~126 λ²”μœ„μ˜ μ‹­μ§„ μ½”λ“œμ— λŒ€μ‘ν•œλ‹€

좜처: Wikimedia Commons, public domain

이 사싀은 μ •λ‹΅ 검증에도 쓰인닀. μ „μˆ˜μ‘°μ‚¬λ‘œ λ‚˜μ˜¨ p 후보가 μ‹€μ œ 평문이라면, κ·Έ μˆ«μžλŠ” λ°˜λ“œμ‹œ μœ νš¨ν•œ ASCII μ½”λ“œ(λŒ€λž΅ 32~126)λ“€λ‘œ κΉ”λ”ν•˜κ²Œ μͺΌκ°œμ Έμ•Ό ν•œλ‹€. 아무 μ •μˆ˜λ‚˜ λ˜λŠ” 게 μ•„λ‹ˆλΌ "ASCII둜 μ½νžˆλŠ” μ •μˆ˜"λΌλŠ” 쑰건이 정닡을 ν•œ 번 더 걸러 μ€€λ‹€.



πŸ’£ 핡심 β€” 뢀정방정식을 μ •μˆ˜ 쑰건으둜 λ‹«λŠ”λ‹€

식을 p에 λŒ€ν•΄ ν’€λ©΄ 이렇닀.

p = 4Β·q / ( key1^4 βˆ’ 95^4 )

key1 ν•˜λ‚˜λ₯Ό λͺ¨λ₯΄λ‹ˆ λ―Έμ§€μˆ˜κ°€ λ‘˜(값이 ν•˜λ‚˜λ‘œ μ•ˆ μ •ν•΄μ§€λŠ” 뢀정방정식)처럼 λ³΄μ΄μ§€λ§Œ, μ—¬κΈ°μ—” κ°•ν•œ μ œμ•½μ΄ 두 개 λΆ™λŠ”λ‹€.

  • pλŠ” μ–‘μ˜ μ •μˆ˜μ—¬μ•Ό ν•œλ‹€ (λ‚˜λˆ—μ…ˆμ΄ λ”± λ–¨μ–΄μ Έμ•Ό ν•œλ‹€).
  • κ·Έ μ •μˆ˜λŠ” ASCII μ½”λ“œμ˜ λ‚˜μ—΄μ΄μ–΄μ•Ό ν•œλ‹€.

key1을 1..94둜 ν›‘μœΌλ©° 4qκ°€ (key1^4 βˆ’ 95^4)둜 λ‚˜λˆ„μ–΄λ–¨μ–΄μ§€λŠ” 경우만 남기면 후보가 ν™• μ€€λ‹€. 거기에 "ASCII둜 μ½νžˆλŠ”κ°€"λ₯Ό λ”ν•˜λ©΄ μ •λ‹΅ key1이 μœ μΌν•˜κ²Œ λ‚¨λŠ”λ‹€. 쒁은 ν‚€ 곡간 + μ •μˆ˜/포맷 μ œμ•½μ˜ 쑰합이 이런 λΆ€μ •λ°©μ •μ‹ν˜• 문제λ₯Ό ν‘ΈλŠ” μ „ν˜•μ μΈ μ—΄μ‡ λ‹€.

β–ΆπŸ› μ‚½μ§ˆ β€” key1 λ²”μœ„λ₯Ό 잘λͺ» 읽어 ν—€λ§΄

μ²˜μŒμ—” while key2 < key1을 "μ’…λ£Œ μ‹œ key2 < key1"둜 착각해 key1을 96..99둜 작고 λŒλ Έλ‹€. λ‹Ήμ—°νžˆ μ •μˆ˜λ‘œ λ–¨μ–΄μ§€λŠ” key1이 μ—†μ–΄ 후보가 0κ°œμ˜€λ‹€. λ£¨ν”„μ˜ μ’…λ£Œ 쑰건(참인 λ™μ•ˆ 반볡 β†’ μ’…λ£Œ μ‹œ 쑰건 κ±°μ§“)을 λ‹€μ‹œ 짚고 λ‚˜μ„œμ•Ό key1 <= 95, q<0κΉŒμ§€ 더해 1..94둜 μ’ν˜”κ³ , κ·Έμ œμ•Ό key1 = 38μ—μ„œ κΉ”λ”ν•œ μ •μˆ˜ pκ°€ λ‚˜μ™”λ‹€.


🎯 풀이 β€” key1 μ „μˆ˜μ‘°μ‚¬

key1을 1..94둜 돌리며 pκ°€ μ–‘μ˜ μ •μˆ˜μΈμ§€, ASCII둜 μͺΌκ°œμ§€λŠ”μ§€ ν™•μΈν•œλ‹€.

# solve.py
from fractions import Fraction
n, key2 = 3, 95
q = -200640142664324295933714
for key1 in range(1, 95):
    denom = key1**(n+1) - key2**(n+1)
    p = Fraction(q*(n+1), denom)
    if p.denominator == 1 and p.numerator > 0:      # μ •μˆ˜ & μ–‘μˆ˜
        s = str(p.numerator)
        dec, i, ok = "", 0, True
        while i < len(s):                           # 2~3자리 ord 둜 그리디 λ””μ½”λ“œ
            for L in (2, 3):
                if i+L <= len(s) and 32 <= int(s[i:i+L]) <= 126:
                    dec += chr(int(s[i:i+L])); i += L; break
            else:
                ok = False; break
        print(f"key1={key1}  p={p.numerator}")
        if ok: print(f"  decodes-> {dec!r}")

solve.py μ‹€ν–‰ β€” key1=38 μ—μ„œ p=10112210997116104 κ°€ μ •μˆ˜λ‘œ λ–¨μ–΄μ§€κ³  "ezmath" 둜 μ½νžŒλ‹€
solve.py μ‹€ν–‰ β€” key1=38 μ—μ„œ p=10112210997116104 κ°€ μ •μˆ˜λ‘œ λ–¨μ–΄μ§€κ³  "ezmath" 둜 μ½νžŒλ‹€

key1 = 38μ—μ„œ p = 10112210997116104κ°€ λ‚˜μ˜€κ³ , 이λ₯Ό 두세 μžλ¦¬μ”© 끊으면 101 122 109 97 116 104 = ord('e','z','m','a','t','h') = "ezmath"둜 κΉ”λ”ν•˜κ²Œ μ½νžŒλ‹€. readme.txtλŠ” "λ³΅ν˜Έν•œ pλ₯Ό λ„£μœΌλΌ"κ³  ν–ˆμœΌλ‹ˆ, ν”Œλž˜κ·ΈλŠ” κ·Έ 숫자 p μžμ²΄λ‹€.

FLAG: DH{10112210997116104}



πŸ“ κ²°λ‘ 

ν‚€κ°€ 두 κ°œλΌλ„ ν•˜λ‚˜κ°€ 곡개되고 ν•˜λ‚˜κ°€ 쒁으면 끝이닀.

μ•”ν˜Έμ‹μ€ 두 ν‚€μ˜ κ±°λ“­μ œκ³± μ°¨μ΄λΌλŠ” κ·ΈλŸ΄μ‹Έν•œ λͺ¨μ–‘을 ν•˜κ³  μžˆμ§€λ§Œ, ν•œ ν‚€κ°€ 곡개되고 λ‹€λ₯Έ ν‚€λŠ” 100 λ―Έλ§Œμ΄λΌλŠ” μˆœκ°„ μ‹€μ œ 비밀은 100가지도 μ•ˆ λœλ‹€. ν‚€ 곡간이 μž‘μœΌλ©΄ ꡬ쑰가 λ³΅μž‘ν•΄λ„ μ „μˆ˜μ‘°μ‚¬κ°€ 닡이닀.

μ •μˆ˜Β·ν¬λ§· μ œμ•½μ€ κ·Έ 자체둜 방정식이닀.

λ―Έμ§€μˆ˜κ°€ ν•˜λ‚˜ 남은 뢀정방정식이라도, "μ •μˆ˜λ‘œ λ–¨μ–΄μ Έμ•Ό ν•œλ‹€", "ASCII둜 μ½ν˜€μ•Ό ν•œλ‹€" 같은 μ œμ•½μ„ κ±Έλ©΄ ν•΄κ°€ ν•˜λ‚˜λ‘œ λ‹«νžŒλ‹€. μžμ—°μ–΄ ν‰λ¬Έμ΄λΌλŠ” μ„±μ§ˆκ³Ό μ •μˆ˜ λ‚˜λˆ—μ…ˆμ΄λΌλŠ” μ„±μ§ˆμ„ νŒλ³„μžλ‘œ μ“°λŠ” 것은 crypto λ¬Έμ œμ—μ„œ 두고두고 ν†΅ν•˜λŠ” 지름길이닀.

이 글이 도움이 λλ‚˜μš”?

Comments

λŒ“κΈ€

0개

λŒ“κΈ€μ„ 남기렀면 둜그인이 ν•„μš”ν•΄μš”. (넀이버 Β· ꡬ글 계정)

λŒ“κΈ€ λΆˆλŸ¬μ˜€λŠ” 쀑…

Related

κ΄€λ ¨ κΈ€

3개
[πŸ₯‰ Bronze 1] 두 μˆœμ—΄λ‘œ λ§Œλ“  clock ν‚€μŠ€νŠΈλ¦Ό λ˜λ§žμΆ”κΈ° β€” DreamHack Basic of crypto 풀이
blog

[πŸ₯‰ Bronze 1] 두 μˆœμ—΄λ‘œ λ§Œλ“  clock ν‚€μŠ€νŠΈλ¦Ό λ˜λ§žμΆ”κΈ° β€” DreamHack Basic of crypto 풀이

ν”Œλž˜κ·Έ 64λ°”μ΄νŠΈλ₯Ό clock μ œλ„ˆλ ˆμ΄ν„°κ°€ λ§Œλ“  ν‚€μŠ€νŠΈλ¦Όκ³Ό XORν•œ 문제. ν‚€μŠ€νŠΈλ¦Ό 값은 두 μˆœμ—΄ H, M으둜 keystream[i] = 8Β·H[i//8] + M[i%8] 처럼 κ²°μ •λ˜λŠ”λ°, μ•Œλ €μ§„ 평문(DH{, }, λŒ€λ¬Έμžμ™€ λ°‘μ€„λ§Œ) μ œμ•½μ΄ κ°•ν•΄ μˆœμ—΄μ„ μ „μˆ˜μ‘°μ‚¬ν•˜λ©΄ μœ μΌν•œ ν”Œλž˜κ·Έκ°€ λ³΅μ›λœλ‹€. μ‹€μ œλ‘œ 40320κ°€μ§€ H μˆœμ—΄ 쀑 39092λ²ˆμ§Έμ—μ„œ 정닡이 λ‚˜μ˜€κ³ , κ±Έλ¦° μ‹œκ°„μ€ 0.14μ΄ˆλΏμ΄λ‹€.
#dreamhack#ctf#crypto+4
2026-07-14#dreamhack +4
[πŸ₯‰ Bronze 3] 16λΉ„νŠΈ μ‹œλ“œμ§œλ¦¬ 슀트림 μ•”ν˜Έ μ „μˆ˜μ‘°μ‚¬ β€” DreamHack STREAMer-Prototype 풀이
blog

[πŸ₯‰ Bronze 3] 16λΉ„νŠΈ μ‹œλ“œμ§œλ¦¬ 슀트림 μ•”ν˜Έ μ „μˆ˜μ‘°μ‚¬ β€” DreamHack STREAMer-Prototype 풀이

16λΉ„νŠΈ μƒνƒœλ₯Ό λΉ„νŠΈ νšŒμ „μ‹œμΌœ ν‚€μŠ€νŠΈλ¦Όμ„ λ§Œλ“œλŠ” 슀트림 μ•”ν˜Έλ‘œ ν”Œλž˜κ·Έλ₯Ό XORν•œ 문제. μ‹œλ“œκ°€ getrandbits(16)이라 경우의 μˆ˜κ°€ 65,536개뿐이고, ν”Œλž˜κ·Έκ°€ DH둜 μ‹œμž‘ν•œλ‹€λŠ” 쑰건으둜 μ •λ‹΅ μ‹œλ“œλ₯Ό κ°€λ €λ‚Έλ‹€. μ‹€μ œλ‘œ μ „μˆ˜μ‘°μ‚¬λ₯Ό 돌렀보면 65536개 쀑 접두사 쑰건을 λ§Œμ‘±ν•˜λŠ” μ‹œλ“œλŠ” μ •ν™•νžˆ ν•˜λ‚˜λΏμ΄λΌ, μš°μ—°νžˆ 걸릴 μœ„ν—˜ 없이 ν™•μ‹€ν•˜κ²Œ 정닡이 κ°€λ €μ§„λ‹€.
#dreamhack#ctf#crypto+3
2026-07-13#dreamhack +4
[πŸ₯‰ Bronze 4] ν‚€ 곡간이 62,500뿐인 μ•„ν•€ μ•”ν˜Έ β€” DreamHack Affe!n 풀이
blog

[πŸ₯‰ Bronze 4] ν‚€ 곡간이 62,500뿐인 μ•„ν•€ μ•”ν˜Έ β€” DreamHack Affe!n 풀이

λΉ„λ°€ λ¬Έμž₯을 GF(251) μœ„ μ•„ν•€ μ•”ν˜Έλ‘œ κ°€λ¦° 문제. ν‚€κ°€ 두 λ°”μ΄νŠΈ(각 1~250)뿐이라 κ°€λŠ₯ν•œ ν‚€μŒμ΄ 62,500κ°œμ— λΆˆκ³Όν•˜κ³ , 평문에 "cryptography"κ°€ λ“€μ–΄ μžˆλ‹€λŠ” 쑰건으둜 유일 ν‚€λ₯Ό νŠΉμ •ν•  수 μžˆλ‹€. μ „μˆ˜μ‘°μ‚¬λ‘œ ν‚€λ₯Ό μ°Ύμ•„ λ³΅ν˜Έν•˜λ©΄ λ¬Έμž₯ 끝에 ν”Œλž˜κ·Έκ°€ λ‚˜μ˜¨λ‹€.
#dreamhack#ctf#crypto+3
2026-07-13#dreamhack +4