๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿด‍โ˜ ๏ธ CTF ๐Ÿด‍โ˜ ๏ธ/๐Ÿงฎ ์•”ํ˜ธํ•™ ๐Ÿงฎ

[Dream Hack - Crypto] Double DES

๋ฐ˜์‘ํ˜•

Double Encryption

์•”ํ˜ธํ‚ค ์ „์ˆ˜์กฐ์‚ฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด? ์•”ํ˜ธํ‚ค ํฌ๊ธฐ๋ฅผ ๋Š˜์ด๋ฉด ๋œ๋‹ค!

์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ Cipher1 = Enc(Plan, key1)
๊ฐ•ํ™”๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ : Cipher2 = Enc(Cipher1, key2)
๋ธ”๋ก ํฌ๊ธฐ๋Š” ๊ทธ๋Œ€๋กœ, ์•”ํ˜ธํ‚ค ํฌ๊ธฐ๋Š” 2๋ฐฐ๋กœ ๊ฐ•ํ™”ํ•˜์˜€๋‹ค.

 

๊ณผ์—ฐ ๋‘๋ฐฐ์˜ ์•ˆ์ •์„ฑ์„ ๊ฐ€์งˆ๊นŒ?

Cipher1 = Enc(Plan, key1) → ํ‚ค ํฌ๊ธฐ 2^n ์ผ ๋•Œ, Cipher2 = Enc(Cipher1, key2) → ํ‚ค ํฌ๊ธฐ 2^2n์„ ๊ธฐ๋Œ€ํ•˜์ง€๋งŒ MITM attack ์„ ์ด์šฉํ•˜๋ฉด 2^(n+1)๋กœ ๊ณต๊ฒฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

MITM (Meet In The Middle) ์ด๋ž€?

์ฃผ์–ด์ง„ (ํ‰๋ฌธ(P), ์•”ํ˜ธ๋ฌธ(C)) ์Œ์— ๋Œ€ํ•˜์—ฌ, ์•”ํ˜ธํ‚ค key1, key2๋ฅผ ์ฐพ๋Š” ๊ณต๊ฒฉ

ํ‰๋ฌธ P ๋ฅผ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  key1์œผ๋กœ ์•”ํ˜ธํ™” ํ•˜์—ฌ ์‚ฌ์ „์— ์ €์žฅํ•œ๋‹ค.

์•”ํ˜ธ๋ฌธ C๋ฅผ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  key2๋กœ ๋ณตํ˜ธํ™” ํ•˜์—ฌ ์ €์žฅํ•œ ์‚ฌ์ „์—์„œ ์ฐพ๋Š”๋‹ค.

 

ํ’€์ด ๊ณผ์ •

from Crypto.Cipher import DES 
import signal 
import os 

if __name__ == "__main__":
    # ํ”„๋กœ๊ทธ๋žจ์„ 15์ดˆ ํ›„์— ์ข…๋ฃŒํ•˜๋„๋ก ์•Œ๋žŒ ์„ค์ •
    signal.alarm(15)

    with open("flag", "rb") as f:
        flag = f.read()
    
    ## key : 'Dream_' + 4๋ฐ”์ดํŠธ์˜ ๋žœ๋ค  + 'Hacker'
    key = b'Dream_' + os.urandom(4) + b'Hacker'

		## key ๋ฅผ 8byte ์”ฉ ๋‚˜๋ˆ”
    key1 = key[:8]
    key2 = key[8:]
    
    print("4-byte Brute-forcing is easy. But can you do it in 15 seconds?")
    
    # key1, key2๋ฅผ ์‚ฌ์šฉํ•˜๋Š” DES ์˜ค๋ผํด ์ƒ์„ฑ
    cipher1 = DES.new(key1, DES.MODE_ECB)
    cipher2 = DES.new(key2, DES.MODE_ECB)
    
    # Double Encryption ์•”๋ณตํ˜ธํ™” ํ•จ์ˆ˜ ์ •์˜
    encrypt = lambda x: cipher2.encrypt(cipher1.encrypt(x))
    decrypt = lambda x: cipher1.decrypt(cipher2.decrypt(x))

    # 'DreamHack_blocks'๋ฅผ Double Encryption ํ•œ ์•”ํ˜ธ๋ฌธ ์ œ๊ณต
    print(f"Hint for you :> {encrypt(b'DreamHack_blocks').hex()}")

    # ์•„๋ž˜์˜ 'give_me_the_flag'์˜ ์•”ํ˜ธ๋ฌธ์„ ์ „๋‹ฌํ•˜๋ฉด flag๋ฅผ ์–ป๋Š” ํ˜•์ƒ‰
    msg = bytes.fromhex(input("Send your encrypted message(hex) > "))
    
    if decrypt(msg) == b'give_me_the_flag':
        print(flag)
    else:
        print("Nope!")

  1. Cipher1์˜ ํ‚ค 2๋ฐ”์ดํŠธ๋ฅผ ๋ชจ๋‘ ๋Œ€์ž…ํ•˜์—ฌ b‘DreamHack_blocks’๋ฅผ ์•”ํ˜ธํ™˜ ๊ฐ’์„ ์‚ฌ์ „์— ์ €์žฅํ•œ๋‹ค. ์‚ฌ์ „์—๋Š” { ์•”ํ˜ธ๋ฌธ : 2๋ฐ”์ดํŠธ ํ‚ค} ํ˜•ํƒœ๋กœ ์ €์žฅํ•œ๋‹ค.
  2. ํ†ต์‹ ์œผ๋กœ ์•”ํ˜ธ๋ฌธ์„ ๋ฐ›๊ณ , cipher2์˜ ํ‚ค 2๋ฐ”์ดํŠธ๋ฅผ ๋Œ€์ž…ํ•˜์—ฌ ๋ณตํ˜ธํ™”ํ•œ๋‹ค. ์ด ๊ฐ’์ด 1์—์„œ ๋งŒ๋“  ์‚ฌ์ „์— ์žˆ์œผ๋ฉด ๊ทธ ๋•Œ, ์‚ฌ์ „์˜ 2 ๋ฐ”์ดํŠธ ํ‚ค ๊ฐ’๊ณผ, cipher2๋ฅผ ๋ณตํ˜ธํ™”ํ•œ ํ‚ค ๊ฐ’์„ ์ „์ฒดํ‚ค๋กœ ํ™•์ •ํ•œ๋‹ค.
  3. ์•ž์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์ฐพ์€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ b‘give_me_the_flag’๋ฅผ ์•”ํ˜ธํ™˜ ๊ฐ’์„ ์„œ๋ฒ„๋กœ ์ „๋‹ฌํ•œ๋‹ค.

 

ํ’€์ด ์ฝ”๋“œ

from Crypto.Cipher import DES
from pwn import * 

key = b'Dream_' + bytearray(4) + b'Hacker'  # ํ‚ค ํ˜•์‹ ์ •์˜: 'Dream_' + 4๋ฐ”์ดํŠธ์˜ ๋นˆ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด + 'Hacker'

# key1์˜ ๋ถ€๋ถ„์„ ๋ธŒ๋ฃจํŠธํฌ์‹ฑํ•˜์—ฌ ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฐ’์— ๋Œ€ํ•ด ์•”ํ˜ธํ™”๋œ ํ…์ŠคํŠธ๋ฅผ ์ €์žฅ
m = {}
for i in range(0, 256 * 256):
    key1 = key[:6] + int.to_bytes(i, 2, 'big')
    cipher1 = DES.new(key1, DES.MODE_ECB)
    cipher_text = cipher1.encrypt(b'DreamHack_blocks')  # 'DreamHack_blocks' ๋ฌธ์ž์—ด ์•”ํ˜ธํ™”
    m[cipher_text] = int.to_bytes(i, 2, 'big')  # {"key1๋กœ ์•”ํ˜ธํ™”๋œ ์•”ํ˜ธ๋ฌธ", "key1์˜ "}

r = remote('host3.dreamhack.games', 18638)
data = r.recvline()
data = r.recvline()[16: -1]
print(data)

# 16์ง„์ˆ˜๋กœ ๋œ ์•”ํ˜ธํ™”๋œ ๊ฐ’์„ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜
cipher_text3 = int.to_bytes(int(data, 16), 16, 'big')
ans = 0
# key2๋ฅผ ๋ธŒ๋ฃจํŠธํฌ์‹ฑํ•˜์—ฌ ๋ณตํ˜ธํ™”ํ•œ ๊ฐ’์ด ๋”•์…”๋„ˆ๋ฆฌ์— ์žˆ๋Š”์ง€ ํ™•์ธ.
for i in range(0, 256 * 256):
    key2 = int.to_bytes(i, 2, 'big') + key[10:]
    cipher2 = DES.new(key2, DES.MODE_ECB)
    cipher_text2 = cipher2.decrypt(cipher_text3)
    if cipher_text2 in m:
        ans = m.get(cipher_text2) + int.to_bytes(i, 2, 'big')

# ๋‘ ๊ฐœ์˜ ํ‚ค ๋ถ€๋ถ„์œผ๋กœ DES ์•”ํ˜ธ ๊ฐ์ฒด ์ƒ์„ฑ
cipher1 = DES.new(key[:6] + ans[:2], DES.MODE_ECB)
cipher2 = DES.new(ans[2:] + key[10:], DES.MODE_ECB)
# 'give_me_the_flag' ๋ฌธ์ž์—ด์„ ์ด์ค‘ DES๋กœ ์•”ํ˜ธํ™”
send_msg = cipher2.encrypt(cipher1.encrypt(b'give_me_the_flag'))

print(send_msg.hex())
r.sendline(send_msg.hex().encode('ascii')) 
r.interactive()

๋ฐ˜์‘ํ˜•