반응형
풀이
#!/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()
서버에 접속하면, AES 암호로 암호화된 token + test
를 받고, IV 값과 Message 값을 보낼 수 있다.
그리고 보낸 IV와 Message로 암호화한 데이터를 받는다.
그 뒤로 보낸 암호화를 복호화 해준다. 만약 복호화 데이터가 token + show
가 맞으면 flag를 출력해준다.
여기서 우리가 조작해야할 부분은 test를 show로 만드는 것이다.
암호화 구조를 보면 16byte씩 나눠 IV로 xor 하고 key로 암호화를 한다. 그리고 뒤 데이터는 앞 cipher text를 IV 값으로 사용한다.
token(160) + test(4) + pad(14)
마지막 뒤에 test+pad
를 암호화할 때는 token의 마지막 16byte를 암호화한 데이터를 VI로 사용해서 xor 연산하고 암호화를 한다.
만약 token의 마지막 16byte를 VI로 사용해서 show
를 암호화해서 test
암호화된 부분을 빼고 show
암호화 데이터를 보내면, flag를 얻을 수 있다.
Solve Code
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from base64 import b64decode, b64encode
from pwn import *
r = remote('35.200.115.41', 16001)
print(r.recvuntil('test Command: '))
test_enc = b64decode(r.recvuntil('\n', drop=True))
real_iv = test_enc[:16]
enc_data = test_enc[16:176]
log.info(f'iv: {real_iv}')
log.info(f'enc_data: {enc_data}')
print(len(enc_data))
pad = test_enc[176:]
log.info(f'pad: {pad}, len: {len(pad)}')
print()
enc_16byte = test_enc[160:176]
print(r.sendlineafter('IV...: ', b64encode(enc_16byte)))
msg = b'show'
print(r.sendlineafter('Message...: ', b64encode(msg)))
print(r.recvuntil('Ciphertext:'))
cipher_text = b64decode(r.recvuntil('\n', drop=True))
print(cipher_text)
print(f'len: {len(cipher_text)}')
show_data = cipher_text[16:]
log.info(f'show_data: {show_data}, len: {len(show_data)}')
data = real_iv + enc_data[:160] + show_data
print(data)
print(r.sendlineafter('Enter your command: ', b64encode(data)))
r.interactive()
Flag
LINECTF{warming_up_crypto_YEAH}
반응형
'CTF(Capture The Flag) > Line 2021' 카테고리의 다른 글
babycrypto3 (0) | 2021.03.22 |
---|---|
babycrypto2 (0) | 2021.03.22 |