127 lines
4.2 KiB
Python
127 lines
4.2 KiB
Python
import asyncio
|
|
import base64
|
|
import logging
|
|
import random
|
|
import subprocess
|
|
from asyncio import StreamReader, StreamWriter
|
|
|
|
from Crypto.Cipher import AES
|
|
|
|
from pwn_utils import utils
|
|
|
|
log = logging.getLogger(__name__)
|
|
clients = {} # task -> (reader, writer)
|
|
|
|
KEY = random.randbytes(16)
|
|
FACT_STORE = {
|
|
1: 'Rumors say that the most important secret is secret number 1337',
|
|
2: 'The 6 security goals are Confidentiality, Integrity, Availability, Authenticity, Accountability and Controlled Access.',
|
|
3: 'One of the first Computer Worms was the Morris Worm in 1988 (https://en.wikipedia.org/wiki/Morris_worm).',
|
|
4: 'Cloudflare uses a wall of lava lamps to generate randomness (https://blog.cloudflare.com/lavarand-in-production-the-nitty-gritty-technical-details/).',
|
|
}
|
|
|
|
SECRET_STORE = {
|
|
42: 'Answer to the Ultimate Question of Life, The Universe, and Everything',
|
|
}
|
|
|
|
|
|
def pkcs7(message: bytes, block_size: int = 16) -> bytes:
|
|
gap_size = block_size - (len(message) % block_size)
|
|
return message + bytes([gap_size] * gap_size)
|
|
|
|
|
|
def cbc_mac(message: bytes, iv: bytes, key: bytes) -> bytes:
|
|
cipher = AES.new(key, AES.MODE_CBC, iv)
|
|
message = pkcs7(message)
|
|
last_block = cipher.encrypt(message)[-16:]
|
|
return last_block
|
|
|
|
|
|
def handle_message(message: bytes, iv: bytes, mac: bytes) -> str:
|
|
kvs = [term.split(b'=') for term in message.split(b'&')]
|
|
args = {key: value for key, value in kvs}
|
|
type = args.get(b'type', b'')
|
|
number = int(args.get(b'number', b'0'))
|
|
|
|
expected_mac = cbc_mac(message, iv, KEY)
|
|
if expected_mac != mac:
|
|
if type == b'secrets':
|
|
# don't give any info for secrets
|
|
return 'MAC verification failed'
|
|
return f'MAC verification failed: expected {expected_mac.hex()}, got {mac.hex()}'
|
|
if type == b'funfact':
|
|
return FACT_STORE.get(number, 'No funfact available')
|
|
if type == b'secrets':
|
|
if number == 1337:
|
|
return subprocess.check_output('flag').decode()
|
|
return SECRET_STORE.get(number, 'No secret available')
|
|
return 'Unknown type'
|
|
|
|
|
|
async def handle_client(client_reader: StreamReader, client_writer: StreamWriter):
|
|
try:
|
|
remote = client_writer.get_extra_info('peername')
|
|
if remote is None:
|
|
log.error('Could not get ip of client')
|
|
return
|
|
remote = '%s:%s' % (remote[0], remote[1])
|
|
log.info('new connection from: %s' % remote)
|
|
except Exception as e:
|
|
log.error('EXCEPTION (get peername): %s (%s)' % (e, type(e)))
|
|
return
|
|
|
|
try:
|
|
while True:
|
|
message = await utils.read_line_safe(client_reader)
|
|
if message is None:
|
|
return
|
|
match message.split(';'):
|
|
case [m, iv, mac]:
|
|
print(m,iv,mac)
|
|
m = base64.b64decode(m)
|
|
iv = base64.b64decode(iv)
|
|
mac = base64.b64decode(mac)
|
|
answer = handle_message(m, iv, mac)
|
|
client_writer.write((answer + '\n').encode())
|
|
continue
|
|
case _:
|
|
client_writer.write(
|
|
'Invalid message, expected format "message;iv;mac"\n'.encode()
|
|
)
|
|
except Exception as e:
|
|
utils.log_error(e, client_writer)
|
|
|
|
|
|
def accept_client(client_reader: StreamReader, client_writer: StreamWriter):
|
|
task = asyncio.Task(handle_client(client_reader, client_writer))
|
|
clients[task] = (client_reader, client_writer)
|
|
|
|
def client_done(task):
|
|
del clients[task]
|
|
client_writer.close()
|
|
log.info('connection closed')
|
|
|
|
task.add_done_callback(client_done)
|
|
|
|
|
|
def main():
|
|
print(KEY)
|
|
# start server
|
|
loop = asyncio.get_event_loop()
|
|
f = asyncio.start_server(accept_client, host=None, port=20205)
|
|
log.info('Server waiting for connections')
|
|
loop.run_until_complete(f)
|
|
loop.run_forever()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s',
|
|
)
|
|
|
|
# "INFO:asyncio:poll took 25.960 seconds" is annyoing
|
|
logging.getLogger('asyncio').setLevel(logging.WARNING)
|
|
|
|
main()
|