또 뭐하지
[Dreamhack] Double DES 본문
풀이
#!/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의 경우 첫번째 키로 암호화해 얻은 암호문과 두번째 키로 복호화해 얻은 평문이 동일한 경우를 찾아두 개의 암호키를 한 번에 찾을 수 있다. 이러한 공격을 중간자 공격(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 |