또 뭐하지

[Dreamhack] Double DES 본문

Write-up/Crypto

[Dreamhack] Double DES

mameul 2024. 9. 20. 15:23
728x90

 

풀이

#!/usr/bin/env python3
from Crypto.Cipher import DES
import signal
import os

if __name__ == "__main__":
    signal.alarm(15)

    with open("flag", "rb") as f:
        flag = f.read()
    
    key = b'Dream_' + os.urandom(4) + b'Hacker'
    key1 = key[:8]
    key2 = key[8:]
    print("4-byte Brute-forcing is easy. But can you do it in 15 seconds?")
    cipher1 = DES.new(key1, DES.MODE_ECB)
    cipher2 = DES.new(key2, DES.MODE_ECB)
    encrypt = lambda x: cipher2.encrypt(cipher1.encrypt(x))
    decrypt = lambda x: cipher1.decrypt(cipher2.decrypt(x))

    print(f"Hint for you :> {encrypt(b'DreamHack_blocks').hex()}")

    msg = bytes.fromhex(input("Send your encrypted message(hex) > "))
    if decrypt(msg) == b'give_me_the_flag':
        print(flag)
    else:
        print("Nope!")

문제에서 제공된 파일을 살펴보자.

 

signal.alarm(15) : 15초 시간제한

key = b'Dream_' + os.urandom(4) + b'Hacker' : 랜덤 4바이트를 받아서 키를 구성

encrypt = lambda x: cipher2.encrypt(cipher1.encrypt(x)) : key를 앞뒤 8바이트씩 쪼개서 DES를 두 번 진행하는 방식으로 암호화

if decrypt(msg) == b'give_me_the_flag': print(flag) : give_me_the_flag를 암호화한 값(16진수 문자열)을 입력하면 flag를 획득

** bytes.fromhex(hex_string) : 16진수 문자열을 바이트 객체로 변환

 

https://gaeko-security-hack.tistory.com/102

 

[암호] DES

DES 알고리즘이 뭔지 알기 전에 블록암호와 블록암호의 구조에 대해 생각하여 보자. 블록암호는 주로 단순한 함수를 반복적으로 적용해서 암호학적으로 강한 함수를 만드는 과정으로 개발된다.

gaeko-security-hack.tistory.com

이중으로 사용된 DES의 경우 첫번째 키로 암호화해 얻은 암호문과 두번째 키로 복호화해 얻은 평문이 동일한 경우를 찾아두 개의 암호키를 한 번에 찾을 수 있다. 이러한 공격을 중간자 공격(Meet-in-the-Middle Attack)이라고 한다.

DES의 키 길이는 56비트이므로 가능한 키의 수는 2**56가지이고, double DES는 (2**25)x(2**25) = 2**112가지이다. 하지만 중간자공격을 사용하면 약 2**57번의 연산으로 키를 찾을 수 있다고 한다.

- 2**56개의 plain_text를 암호화 과정에서 계산한 후 저장하고,

- 2**56개의 cipher_text를 복화화한 값과 비교하는 방식으로 공격을 수행 

 

이 문제에서는 랜덤부분이 4바이트 뿐이므로 더 적은 양의 연산으로 비밀키를 알아낼 수 있다.

print(f"Hint for you :> {encrypt(b'DreamHack_blocks').hex()}") 부분이 제공되므로 DreamHack_blocks를 사전에 암호화해서 저장해두고, 서버에서 제공된 암호문을 복화하여 대조하면 된다.

from pwn import *
from Crypto.Cipher import DES

# DreamHack_blocks를 암호화한 값을 딕셔너리의 키로, 암호화에 사용된 키값을 딕셔너리의 값으로 저장
m = {}
for i in range(2**16):
    key1 = b'Dream_' + i.to_bytes(2,'big')
    cipher1 = DES.new(key1, DES.MODE_ECB)
    cipher_text = cipher1.encrypt(b'DreamHack_blocks')
    m[cipher_text] = key1
    
r = remote('host3.dreamhack.games',8920)
r.recvuntil(b':>')
data = bytes.fromhex(r.recvline().decode())
# DreamHack_blocks 암호화한 값을 바이트형태로 받아옴
print(data)

# 받아온 값을 복호화
for i in range(2**16):
    key2 = i.to_bytes(2,'big') + b'Hacker'
    cipher = DES.new(key2, DES.MODE_ECB)
    dec = cipher.decrypt(data)
    
    # 복호화한 값이 딕셔너리 m에 존재하면 비밀키 획득
    if dec in m:
        k1 = m[dec]
        k2 = key2
        break

cipher1 = DES.new(k1, DES.MODE_ECB)
cipher2 = DES.new(k2, DES.MODE_ECB)

#획득한 비밀키로 give_me_the_flag를 암호화하여 서버에 전달
send_msg = cipher2.encrypt(cipher1.encrypt(b'give_me_the_flag'))
print(send_msg.hex())

r.sendlineafter(b'> ', send_msg.hex().encode())
r.interactive()

위 내용을 코드로 작성하여 실행해보면 flag를 얻을 수 있다.

 

아직도 형식변환이 헷갈리는 슬픈 현실..

'Write-up > Crypto' 카테고리의 다른 글

[Dreamhack] STREAMer-Prototype  (0) 2024.10.04
[Dreamhack] No Shift Please!  (4) 2024.09.27
[Dreamhack] ICM2022  (0) 2024.09.13
[Dreamhack] Robot Only  (0) 2024.05.13
[Dreamhack] RSA-wiener  (1) 2024.05.01