Hacking/Write Up

[Cryptography] Textbook-CBC

min_zu 2024. 8. 3. 15:49
728x90
반응형

문제 : https://dreamhack.io/wargame/challenges/175

 

Textbook-CBC

Description 드림이가 AES 플래그 서버를 운영하고 있어요. 무엇이든 암호화하고 복호화 할 수 있다던데... 플래그를 획득해주세요! References https://dreamhack.io/lecture/courses/74

dreamhack.io

 

Code Analysis

from Crypto.Util.Padding import pad, unpad
from random import choices, randint
from Crypto.Cipher import AES

BLOCK_SIZE = 16
flag = open("flag", "rb").read()
key = bytes(randint(0, 255) for i in range(BLOCK_SIZE))

encrypt = lambda pt: AES.new(key, AES.MODE_CBC, key).encrypt(pad(pt, BLOCK_SIZE))
decrypt = lambda ct: unpad(AES.new(key, AES.MODE_CBC, key).decrypt(ct), BLOCK_SIZE)

print("Welcome to dream's AES server")
while True:
    print("[1] Encrypt")
    print("[2] Decrypt")
    print("[3] Get Flag")

    choice = input()

    if choice == "1":
        print("Input plaintext (hex): ", end="")
        pt = bytes.fromhex(input())
        print(encrypt(pt).hex())

    elif choice == "2":
        print("Input ciphertext (hex): ", end="")
        ct = bytes.fromhex(input())
        print(decrypt(ct).hex())

    elif choice == "3":
        print(f"flag = {encrypt(flag).hex()}")
        exit()

    else:
        print("Nope")
  • encrypt : 운영모드 CBC로 AES 암호화 / 16바이트 패딩
  • decrypt : 운영모드 CBC로 AES 복호화 / 16바이트 언패딩

CBC 모드로 암호화 시 사용되는 iv (초기화 벡터) 값이 key와 같음 

 

Exploit Scenario

0으로 채워진 평문 P를 암호화 하면

\(Enc_k(P \oplus iv) = Enc_k(iv)\) 이다. 

해당 암호화에서 iv = key이므로 0으로 채워진 16바이트 블록을 암호화 하면, \(Enc_k(key)\)를 얻을 수 있다. 

 

CBC 모드의 경우, 이전 블록의 암호화 결과를 해당 블록의 평문과 xor하여 암호화한다. 

따라서 복호화를 할 때

0으로 채워진 16바이트 블록 + \(Enc_k(key)\)를 복호화하면

\(Dec_k(0) \oplus key || Dec_k(Enc_k(key)) \oplus 0\)이 되므로

두번째 블록 [16:32]는 key값이 된다.

 

Exploit

from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import AES
from pwn import *

encrypt = lambda pt: AES.new(key, AES.MODE_CBC, key).encrypt(pad(pt, 16))
decrypt = lambda ct: unpad(AES.new(key, AES.MODE_CBC, key).decrypt(ct), 16)

r = remote(호스트, 포트)

r.sendlineafter("Flag\n", "1")
r.sendlineafter("(hex): ", "00" * 16)
iv = bytes.fromhex(r.recvline(keepends=False).decode())

r.sendlineafter("Flag\n", "2")
r.sendlineafter("(hex): ", "00" * 16 + iv.hex())

key = bytes.fromhex(r.recvline(keepends=False).decode())[16:32]

r.sendlineafter("[3] Get Flag\n", "3")
r.recvuntil("flag = ")
ct = bytes.fromhex(r.recvline(keepends=False).decode())

print(decrypt(ct))

 

피드백

사실 WHS CTF로 나온 문제가 이 문제의 응용이길래 한번 풀어봤다... 

좀 더 응용버전을 앞두고 있어서 그런지 첫 레벨 4문제였는데 어렵지 않게 풀었다

의외로 AES의 암호화 원리에 대한 이해보다는 운영모드의 이해가 더 필요한 문제에 가까웠음

728x90
반응형