#!/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를 두 번 진행하는 방식으로 암호화
여기서 readme 파일을 확인해보면 p 를 구하기 위해 필요한 것 중 모르는 것은 key1 밖에 없는 것을 확인할 수 있다. 이때코드에서 key2 보다 key1 이 작다는 것을 알 수 있고 , key1 은 1~94 까지의 값을 가진다 . 큰 범위가 아니므로 전수조사를 시행한다 .
복호화 공식에 따라 코드를 작성하고, 나누어 떨어지는 경우만 프린트하도록 하면 p 값을 얻을 수 있다 .
N = int(input())
p = []
for _ in range(N):
a, b, c = map(int, input().split())
d = 0
if a == b == c :
d = 10000 + a*1000
elif a == b :
d = 1000 + a*100
elif b == c :
d = 1000 + b*100
elif c == a :
d = 1000 + c*100
else :
d = 100 * max(a, b, c)
p.append(d)
print(max(p))
제공된 코드를 살펴보면 box와 name 모두 크기가 0x40으로 지정되어 있다. box는 정해진 크기만큼 입력을 받고, name은 사용자가 입력한 크기만큼 입력을 받는데 입력 크기 제한이 따로 있지 않아서 이 부분에서 버퍼오버플로우가 발생한다. 그리고 P 부분에서 입력된 인덱스의 box 값을 읽어주는데 따로 입력 인덱스에 제한을 두고 있지 않다. 이 부분에서느 카나리릭이 발생한다.