또 뭐하지

[Dreamhack] No sub please! 본문

Write-up/Crypto

[Dreamhack] No sub please!

mameul 2024. 11. 8. 16:57
728x90

 

풀이

from AES import AES_implemented
import os

# For real AES without modification, this challenge is unsolvable with modern technology.
# But let's remove a step.
ret = lambda x: None
AES_implemented._sub_bytes = ret
AES_implemented._sub_bytes_inv = ret
# Will it make a difference?

secret = os.urandom(16)
key = os.urandom(16)

flag = open("flag.txt", "r").read()

cipher = AES_implemented(key)

secret_enc = cipher.encrypt(secret)
assert cipher.decrypt(secret_enc) == secret
print(f"enc(secret) = {bytes.hex(secret_enc)}")

while True:
	option = int(input("[1] encrypt, [2] decrypt: "))

	if option == 1: # Encryption
		plaintext = bytes.fromhex(input("Input plaintext to encrypt in hex: "))
		assert len(plaintext) == 16

		ciphertext = cipher.encrypt(plaintext)
		print(f"enc(plaintext) = {bytes.hex(ciphertext)}")

		if plaintext == secret:
			print(flag)
			exit()

	elif option == 2: # Decryption
		ciphertext = bytes.fromhex(input("Input ciphertext to decrypt in hex: "))
		assert len(ciphertext) == 16
		
		if ciphertext == secret_enc:
			print("No way!")
			continue
			
		plaintext = cipher.decrypt(ciphertext)
		print(f"dec(ciphertext) = {bytes.hex(plaintext)}")

제공된 코드를 살펴보면, AES의 subbytes 부분을 없애고 secret과 key를 랜덤 16바이트를 받는다. 그리고 enc(secret) 값을 제공해주며 encrypt 옵션에 secret 값을 입력해주면 flag가 출력된다.

 

AES에서 SubBytes는 상태 배열의 각 바이트를 S-box를 참조하여 치환하는 함수이다. 이 치환 과정은 암호의 선형성을 없애, 대칭키 암호에서 혼돈 요건을 충족한다. 

SubBytes를 없애면 선형 관계를 가지게 되어 아래의 성질을 만족하게 된다고 한다.

enc(a) ^ enc(b) = enc(0) ^ enc(a^b)

dec(a) ^ dec(b) = dec(0) ^ dec(a^b)

위 공식을 변형하면 dec(a) = dec(0) ^ dec(a^b) ^ dec(b) 인 것을 알 수 있고 이를 이용하여 필요한 secret을 얻을 수 있을 것 같다.

 

그러면 필요한 것은

dec(0)

dec(enc(secret)^b)  (이 때 b는 아무값이나 써도 괜찮음)

dec(b) 이다

이를 바탕으로 익스플로잇 코드를 작성했다

from pwn import *
import os

r = remote("host3.dreamhack.games", 11147)

r.recvuntil(b'= ')
secret_enc = bytes.fromhex(r.recvline().decode())

b = os.urandom(16) #랜덤한 b를 받아옴

def decrypt(ciphertext): 
    r.sendline(b'2')
    r.sendline(bytes.hex(ciphertext).encode())
    r.recvuntil(b'= ')
    plaintext = bytes.fromhex(r.recvline().decode())
    return plaintext

def xor(a, b):
    result = []
    for i in range(len(a)):
        tmp = a[i] ^ b[i]
        result.append(tmp)
    
    return bytes(result)


p1 = decrypt(bytes(16))          #dec(0)
p2 = decrypt(xor(secret_enc, b)) #dec(secret_enc^b)
p3 = decrypt(b)                  #dec(b)

p = xor(p1, xor(p2, p3)) # p1^p2^p3

r.sendline(b'1')
r.sendline(bytes.hex(p).encode())

r.interactive()

작동시키면 아래와 같이 flag를 얻을 수 있다!

 

* xor 함수  xor = lambda a, b: bytes([i^j for i, j in zip(a,b)]) 이렇게 짜면 간결 zip!!

* 아핀성질에 대해서 더 공부해야할 것 같다

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

[Dreamhack] 40 Birthdays  (0) 2024.11.08
[Dreamhack] Insecure Seed  (0) 2024.10.31
[Dreamhack] Easy Linguistics  (0) 2024.10.24
[Dreamhack] safeprime  (1) 2024.10.24
[Dreamhack] What is This???  (0) 2024.10.04