https://app.hackthebox.com/challenges/124

Description

The Bank of the World is under attack. Hackers found a way in and locked the admins out. However, the netcat authentication by the intruders is not perfectly secure. Could you help the admins log in?

Source

app.py

#!/usr/bin/python3
import socketserver 
import socket, os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad
from Crypto.Random import get_random_bytes
from binascii import unhexlify
from secret import FLAG

wlcm_msg ='########################################################################\n'+\
          '#                  Welcome to the Bank of the World                    #\n'+\
          '#             All connections are monitored and recorded               #\n'+\
          '#      Disconnect IMMEDIATELY if you are not an authorized user!       #\n'+\
          '########################################################################\n'

key = get_random_bytes(16)
iv = get_random_bytes(16)

def encrypt_data(data):
	padded = pad(data.encode(),16,style='pkcs7')
	cipher = AES.new(key, AES.MODE_CBC,iv)
	enc = cipher.encrypt(padded)
	return enc.hex()

def decrypt_data(encryptedParams):
	cipher = AES.new(key, AES.MODE_CBC,iv)
	paddedParams = cipher.decrypt( unhexlify(encryptedParams))
	print(paddedParams)
	if b'admin&password=g0ld3n_b0y' in unpad(paddedParams,16,style='pkcs7'):
		return 1
	else:
		return 0

def send_msg(s, msg):
	enc = msg.encode()
	s.send(enc)

def main(s):
	send_msg(s, 'username: ')
	user = s.recv(4096).decode().strip()
	send_msg(s, user +"'s password: " )
	passwd = s.recv(4096).decode().strip()
	send_msg(s, wlcm_msg)
	msg = 'logged_username=' + user +'&password=' + passwd
	try:
		assert('admin&password=g0ld3n_b0y' not in msg)
	except AssertionError:
		send_msg(s, 'You cannot login as an admin from an external IP.\nYour activity has been logged. Goodbye!\n')
		raise
	msg = 'logged_username=' + user +'&password=' + passwd
	send_msg(s, "Leaked ciphertext: " + encrypt_data(msg)+'\n')
	send_msg(s,"enter ciphertext: ")
	enc_msg = s.recv(4096).decode().strip()
	try:
		check = decrypt_data(enc_msg)
	except Exception as e:
		send_msg(s, str(e) + '\n')
		s.close()
	if check:
		send_msg(s, 'Logged in successfully!\nYour flag is: '+ FLAG)
		s.close()
	else:
		send_msg(s, 'Please try again.')
		s.close()

class TaskHandler(socketserver.BaseRequestHandler):
	def handle(self):
		main(self.request)

if __name__ == '__main__':
	socketserver.ThreadingTCPServer.allow_reuse_address = True
	server = socketserver.ThreadingTCPServer(('0.0.0.0', 1337), TaskHandler)
	server.serve_forever()

Exploitation

#!/usr/bin/env python3
from pwn import remote, sys

def get_process():
    try:
        host, port = sys.argv[1].split(':')
        return remote(host, int(port))
    except IndexError:
        print(f'Usage: python {sys.argv[0]} <ip:port>')
        exit(1)

io = get_process()
io.sendlineafter(b'username: ', b'bdmin')
io.sendlineafter(b'password: ', b'g0ld3n_b0y')
io.recvuntil(b'Leaked ciphertext: ')
ct = bytearray.fromhex(io.recvline().decode())
ct[0] ^= ord('b') ^ ord('a')
io.sendlineafter(b'enter ciphertext: ', ct.hex().encode())  
io.recvline()
io.success(io.recv().decode())

Summary

Flippin Bank: reconstruct the generator state, derive the AES material, and decrypt the final ciphertext.