ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Clear] LINE CTF 2021 babycrypto2 Writeup
    CTF/LINE CTF 2021 2021. 3. 22. 20:37

    주어진 파일을 분석해보자 .

    #!/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()
    
    AES_KEY = get_random_bytes(AES.block_size)
    TOKEN = b64encode(get_random_bytes(AES.block_size*10-1))
    COMMAND = [b'test',b'show']
    PREFIX = b'Command: '
    
    def run_server(client):
        client.send(b'test Command: ' + AESCipher(AES_KEY).encrypt(PREFIX+COMMAND[0]+TOKEN) + b'\n')
        print(len(PREFIX+COMMAND[0]))
        print(len(TOKEN))
        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 == PREFIX+COMMAND[1]+TOKEN:
                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', 16002))
        server.listen(1)
    
        while True:
            client, address = server.accept()
    
            process = multiprocessing.Process(target=run_server, args=(client, ))
            process.daemon = True
            process.start()

    babycrypto1과 달라진 점은, 

    평문의 뒷부분이 아닌 앞부분이 다를 때의 암호문을 구해야 한다는 점이다.

     

    즉 주어진 test Command 의 첫 번째 블록은 [Command: test???] 의 암호문일 것이다.

    (1블록의 길이는 16이므로 뒤에 3바이트는 token의 앞부분일 것이다.)

    우리는 첫 번째 블록이 [Command: show???] 일때의 암호문을 구해야 한다.

     

    다시 CBC 암호화 방식을 보자. 첫 번째 암호 블록은

    임의의 IV XOR Plaintext의 첫 블록 연산 후 암호화가 진행된다.

     

    우선 test command를 그대로 전송해 ???값을 알아 낼 수 있다.

     

    from pwn import *
    import base64
    
    p=remote("35.200.39.68", 16002)
    
    p.recvuntil("test Command: ")
    test = p.recvuntil(b"\nEnter your command: ", drop=True)
    print(test)
    #print(test[-32:-16])
    iv = list(base64.b64decode(test)[:16])
    chiper = base64.b64decode(test)[16:]
    
    for i in range(16):
      iv[i] = 0
    
    iv=bytes(iv)
    
    medium = base64.b64encode(iv+chiper)
    #print(final)
    p.send(test)
    p.recvuntil("test")
    temp_3byte = p.recv(3)
    print(b"temp_3byte: " + temp_3byte)
    
    p.recvuntil(b"Enter your command: ")
    p.send(medium)
    temp_16byte=p.recv(16)
    
    target = b"Command: show"+temp_3byte
    print(target)
    
    last_iv=list(target[i]^temp_16byte[i] for i in range(16))
    print(last_iv)
    
    final = base64.b64encode(bytes(last_iv)+chiper)
    
    p.recvuntil("Enter your command: ")
    p.send(final)
    p.interactive()

     

    또한, 암/복호화 과정에서 첫 번째 블록은 IV와 XOR 연산이 이루어지기 때문에 IV를 0*16으로 조작 한 값에 원하는 평문을 XOR시켜 연산해주면 원하는 평문일 때의 암호문을 얻을 수 있다.

     

    [iv] XOR [Cipher_aftet_aes] = [test] 

    ( [iv] XOR [Cipher_aftet_aes] XOR [test] )  XOR [test] XOR [show] 

    [test] XOR [test] XOR [show] = [show]

     

    < exploit code >

    from pwn import *
    import base64
    
    p=remote("35.200.39.68", 16002)
    
    p.recvuntil("test Command: ")
    test = p.recvuntil(b"\nEnter your command: ", drop=True)
    print(test)
    #print(test[-32:-16])
    iv = list(base64.b64decode(test)[:16])
    chiper = base64.b64decode(test)[16:]
    
    for i in range(16):
      iv[i] = 0
    
    iv=bytes(iv)
    
    medium = base64.b64encode(iv+chiper)
    #print(final)
    p.send(test)
    p.recvuntil("test")
    temp_3byte = p.recv(3)
    print(b"temp_3byte: " + temp_3byte)
    
    p.recvuntil(b"Enter your command: ")
    p.send(medium)
    temp_16byte=p.recv(16)
    #print(b"temp_16byte: "t + temp_16byte)
    
    target = b"Command: show"+temp_3byte
    print(target)
    
    last_iv=list(target[i]^temp_16byte[i] for i in range(16))
    print(last_iv)
    
    final = base64.b64encode(bytes(last_iv)+chiper)
    
    p.recvuntil("Enter your command: ")
    p.send(final)
    p.interactive()

     

    FLAG = LINECTF{echidna_kawaii_and_crypto_is_difficult}

    반응형

    'CTF > LINE CTF 2021' 카테고리의 다른 글

    [Study] LINE CTF 2021 Your note  (0) 2021.03.29
    [Clear] LINE CTF 2021 babycrypto1 Writeup  (0) 2021.03.22
    [Clear] LINE CTF 2021 diveinternal Writeup  (0) 2021.03.22

    댓글

Designed by Tistory.