본문 바로가기

Dreamhack/CryptoPS

[Dreamhack][CryptoPS] [LINE CTF 2021] babycrypto1

728x90

1.문제 분석

  • AES의 CBC모드를 통해 flag를 구하는 문제
  • base64 인코딩과 디코딩이 섞인 문제

2. 기본 아이디어

  1. CBC 모드는 바로 전 블록이 해당 블록의 IV임을 이해한다.
  2. IV를 알면 원하는 암호화 문자열을 만들 수 있다.

3.문제 풀이

 

문제 코드는 아래와 같다.

 

#!/usr/bin/env python
from base64 import b64decode
from base64 import b64encode
import socket
import multiprocessing

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
import hashlib
import sys

class AESCipher:
    def __init__(self, key):
        self.key = key

    def encrypt(self, data):
        iv = get_random_bytes(AES.block_size)
        self.cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return b64encode(iv + self.cipher.encrypt(pad(data, 
            AES.block_size)))

    def encrypt_iv(self, data, iv):
        self.cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return b64encode(iv + self.cipher.encrypt(pad(data, 
            AES.block_size)))

    def decrypt(self, data):
        raw = b64decode(data)
        self.cipher = AES.new(self.key, AES.MODE_CBC, raw[:AES.block_size])
        return unpad(self.cipher.decrypt(raw[AES.block_size:]), AES.block_size)

flag = open("flag", "rb").read().strip()

COMMAND = [b'test',b'show']

def run_server(client, aes_key, token):
    client.send(b'test Command: ' + AESCipher(aes_key).encrypt(token+COMMAND[0]) + b'\n')
    client.send(b'**Cipher oracle**\n')
    client.send(b'IV...: ')
    iv = b64decode(client.recv(1024).decode().strip())
    client.send(b'Message...: ')
    msg = b64decode(client.recv(1024).decode().strip())
    client.send(b'Ciphertext:' + AESCipher(aes_key).encrypt_iv(msg,iv) + b'\n\n')
    while(True):
        client.send(b'Enter your command: ')
        tt = client.recv(1024).strip()
        tt2 = AESCipher(aes_key).decrypt(tt)
        client.send(tt2 + b'\n')
        if tt2 == token+COMMAND[1]:
            client.send(b'The flag is: ' + flag)
            client.close()
            break

if __name__ == '__main__':
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(('0.0.0.0', 16001))
    server.listen(1)

    while True:
        client, address = server.accept()

        aes_key = get_random_bytes(AES.block_size)
        token = b64encode(get_random_bytes(AES.block_size*10))[:AES.block_size*10]

        process = multiprocessing.Process(target=run_server, args=(client, aes_key, token))
        process.daemon = True
        process.start()

 

우선 이 코드를 통해 알 수 있는 점은 다음과 같다.

 

1. AES의 CBC 모드를 쓴다는 것.

2. 사용자가 IV를 입력할 수 있고, 암호화하고 싶은 msg를 작성할 수 있다는 것.

3. 1024 사이즈 만큼의 값을 입력 가능하다는 것.

4. token(160bytes)+b'test'가 주어지고 내가 작성한 암호화된 문자열이 token(160bytes)+b'show'와 같아야 한다는 것.

 

따라서 해야할 행동은 다음과 같다.

 

1. 주어지는 testCommand를 블록단위로 쪼갠 후 b'test' 바로 앞의 블록을 b'show'를 암호화 하기위해 가져온다.

2. b'show'를 찾았다면 앞선 token+b'test'에서 token을 가져온 후 token+b'show'를 base64인코딩해서 입력해준다.

3. 잘 암호화되었다면 tt2 = token+b'show'에 의거해 flag가 나올 것이다.

 

exploit code는 다음과 같다.

 

from pwn import *

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

r.recvuntil("test Command: ")
test = r.recvuntil("\n**Cipher oracle**\n", drop=True)
#print(test)
test = base64.b64decode(test)

iv = test[-32:-16]
#print(iv)

r.recvuntil("IV...: ")
r.send(base64.b64encode(iv))
r.recvuntil("Message...: ")
r.send(base64.b64encode(b'show'))

r.recvuntil("Ciphertext:")
b = r.recvuntil("\n", drop=True)
#print(b)
b = base64.b64decode(b)

final = base64.b64encode(test[:-32]+b)
print(r.sendlineafter("Enter your command: ", final))
r.interactive()

 

728x90