본문 바로가기

보안

[드림핵/암호학] Double DES

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

if __name__ == "__main__":
    signal.alarm(15) #15초 제한 시간

    with open("flag", "rb") as f:
        flag = f.read()
    
    key = b'Dream_' + os.urandom(4) + b'Hacker'
    key1 = key[:8] #key의 앞 8바이트, 뒤 2바이트는 모름
    key2 = key[8:] #key의 뒤 8바이트, 앞 2바이트는 모름
    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)) #cipher1로 암호화 -> cipher2로 암호화
    decrypt = lambda x: cipher1.decrypt(cipher2.decrypt(x)) #cipher2로 복호화 -> cipher1로 복호화

    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!")
  • b'DreamHack_blocks' 암호화 결과가 주어져있으므로 cipher2.encrypt(cipher1.encrypt(b'DreamHack_blocks')) 결과를 이용해 두 키를 완전히 복구
  • 키의 미지 바이트는 총 4바이트, 즉 32비트 => 가지의 키 존재

 

브루트포스

from pwn import *
from Crypto.Cipher import DES
from tqdm import trange

io = remote('host1.dreamhack.games', #)

io.recvuntil(b":> ")
hint = bytes.fromhex(io.recvline().decode())

for i in trange(2**32): #tqdm 라이브러리의 기능, 반복문 진행 상태를 시각적으로 보여줌
	key = b'Dream_' + i.to_bytes(4, "big") + b'Hacker' #0부터 2^32-1까지의 정수를 4바이트로 변환
	key1 = key[:8]
	key2 = key[8:]
	cipher1 = DES.new(key1, DES.MODE_ECB)
	cipher2 = DES.new(key2, DES.MODE_ECB)
	if cipher2.encrypt(cipher1.encrypt(b'DreamHack_blocks')) == hint:
		print("Success")
		break

=> 2^32개의 모든 가능한 값을 시도할 수는 있으나 암, 복호화 연산 시간 때문에 15초 안에 불가능

 

익스플로잇 설계

  • cipher2.encrypt(cipher1.encrypt(b'DreamHack_blocks')) == (암호화된 결과)
  • cipher1.encrypt(b'DreamHack_blocks') == cipher2.decrypt(암호화된 결과) => Meet-in-the-middle attack (가운데서 만난다는 의미)
  • lambda 함수
encrypt = lambda x: cipher2.encrypt(cipher1.encrypt(x))

# 아래 코드와 같은 의미
def encrypt(x):
    return cipher2.encrypt(cipher1.encrypt(x))
    
# 이런 식으로 사용
assert encrypt(b"DreamHack_blocks") == hint

 

 

드림핵은 문법 설명 좀 해줬으면..