CTF/LINE CTF 2021
[Clear] LINE CTF 2021 babycrypto2 Writeup
Vardy
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}
반응형