ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Crypto][CTF]YYYES - AES CBC Attack
    Crypto 2024. 10. 13. 22:59

     

    Description

    - YYY가 AES 플래그 서버를 운영하고 있어요. 무엇이든 암호화하고 복호화 할 수 있다던데… 플래그를 획득해주세요!

     

    - prob.py

    #!/usr/bin/env python3
    from Crypto.Util.Padding import pad, unpad
    from Crypto.Cipher import AES
    import os
    
    BLOCK_SIZE = 16
    flag = open("flag", "rb").read()
    key = os.urandom(BLOCK_SIZE)
    
    # perfectly protected!
    iv = key
    print(iv)
    
    for _ in range(5):
        iv = AES.new(key, AES.MODE_CBC, b'\x00' * 16).encrypt(iv)
    
    print(iv)
    
    encrypt = lambda pt: AES.new(key, AES.MODE_CBC, iv).encrypt(pad(pt, BLOCK_SIZE))
    decrypt = lambda ct: AES.new(key, AES.MODE_CBC, iv).decrypt(ct)
    
    print("Welcome to YYY'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")

     

     

    • 사실 이 형태와 비슷한 워게임 문제가 이미 화이트햇 스쿨 사이트에 ‘Exercise-CBC’ 문제로 있다. 똑같이 AES CBC 모드로 인해 암호화된 flag를 평문-암호문 쌍을 이용해 복호화시켜 답을 알아내는 문제였다.
    • 먼저 CBC 모드에 대해 간단히 개념을 보자.

     

     

    https://dreamhack.io/lecture/courses/552

     

    Dreamhack | 강의 | Dreamhack

     

    dreamhack.io

    더보기

    CBC 모드

    CBC(Cipher Block Chaining) 모드는 어떤 블록을 암호화하기 전에, 이 블록을 직전 블록의 암호문과 XOR합니다. 평문의 첫 번째 블록은 이전 블록이 존재하지 않으므로, **초기 벡터(Initialization Vector, IV)**라고 불리는 임의의 데이터와 XOR합니다. 이 모드를 사용하면 각 블록이 서로의 암호화에 영향을 주므로 같은 블록도 전체 평문 및 IV에 따라 암호화 결과가 달라집니다.

    송신자는 초기 벡터를 암호문의 0번째 블록 C0로 전송합니다. CBC 모드의 암, 복호화를 수학적으로 표현하면 다음과 같습니다.

    암호화 : $C_0=IV,C_i=enc_K(P_i⊕C_{i−1}),i≥1$

    복호화 : $C_0=IV,P_i=dec_K(C_i)⊕C_{i−1},i≥1$

     

    서버로 접속할 때의 화면

    • 이 문제도 동일하게 CBC 모드의 평문-암호문 쌍을 이용하여 key를 알아내어 암호화된 flag를 복호화해야하는데, Exercise-CBC 문제와의 차이점은 key를 IV값을 0으로 하여 5번 암호화한 값을 새로운 IV값으로 설정하여 flag를 암호화했다는 것이다. 이전 문제에서는 IV값을 알아내면 그것이 곧 key였는데, 이 문제에서는 IV값을 알아내는 것에서 끝나지 않는다. 이를 해결하기 위해, 새로운 IV값이 설정된 과정과, 그 IV값을 알아내기 위한 수식을 적어보았다.

     

    Key를 이용하여 IV가 암호화된 과정

    $평문 : K, 암호문 : R_1, R_2, …$

    $R_1=enc_k(K⊕0)=enc_k(K)$

    $R_2=enc_k(R_1⊕0)=enc_k(R_1)$

    $…$

    $R_5=enc_k(R_4⊕0)=enc_k(R_4)=IV$

     

     

     

    평문-암호문 쌍을 이용하여 IV를 얻어내는 과정

    $\text{if } P_1=0, C_1=enc_k(0⊕C_0)=enc_k(IV)$

    $\text{if }C_1=0, C_2=enc_k(IV),$

    $P_1=dec_k(0)⊕IV, P_2=dec_k(enc_k(IV))=IV$

    • 여기서 key를 알아내기 위해 어떤 평문-암호문 쌍을 이용할지를 고민하다가, xor연산을 이용하기 위해 암호문을 IV값( $R_5$ )으로 넣고 복호화를 시킨 식을 변형하면 key를 4번 암호화시킨 $R_4$가 나온다는 사실을 알아냈다.
    • 마찬가지로 암호문을 $R_4$로 넣고 복호화한 식을 변형하면 $R_3$가 나오고, 이를 반복하면 key값이 나온다.

     

     

     

    평문-암호문 쌍을 이용하여 key를 얻어내는 과정

    $\text{if }C=IV, P=dec_k(IV)⊕IV, P⊕IV=dec_k(IV)=dec_k(R_5)=R_4$

    $\text{if }C=R_4, P=dec_k(R_4)⊕IV, P⊕IV=dec_k(R_4)=R_3$

    $…$

    $\text{if }C=R_1, P=dec_k(R_1)⊕IV, P⊕IV=dec_k(R_1)=dec_k(enc_k(K))=K$

    • 얻어낸 key를 가지고 암호화된 flag를 복호화시키면 성공이다

     

     

     

     

     

    - sol.py

    from Crypto.Util.Padding import pad, unpad
    from Crypto.Cipher import AES
    from pwn import *
    
    r = remote("srv1.kitriwhs.kr", 8813)
    
    r.sendlineafter("[3] Get Flag\n", "1")
    r.sendlineafter("(hex): ", "00" * 16)
    blk = bytes.fromhex(r.recvline(keepends=False).decode())
    
    r.sendlineafter("[3] Get Flag\n", "2")
    r.sendlineafter("(hex): ", "00" * 16 + blk.hex())
    iv = bytes.fromhex(r.recvline(keepends=False).decode())[16:32]
    
    dec_iv = iv
    
    for _ in range(5):
        r.sendlineafter("[3] Get Flag\n", "2")
        r.sendlineafter("(hex): ", dec_iv.hex())
        dec_iv = xor(bytes.fromhex(r.recvline()[:-1].decode())[:16],iv)
    
    key = dec_iv
    
    r.sendlineafter("[3] Get Flag\n", "3")
    r.recvuntil("flag = ")
    ct = bytes.fromhex(r.recvline(keepends=False).decode())
    
    flag = AES.new(key, AES.MODE_CBC, iv).decrypt(ct)
    print(flag.decode())

     

    sol.py를 실행시키면 flag가 나온다!

     

    'Crypto' 카테고리의 다른 글

    [Crypto][CTF]hashbrown - Length Extension Attack  (4) 2024.11.13
    [Crypto][CTF]Bigger is Better - RSA Wiener Attack  (1) 2024.10.29
Designed by Tistory.