nc 220.127.116.11 14549
In this challenge, we were given a 32-bit ELF keygenme in C++ which asks for a username and two «tokens».
usage: ./keygenme32.elf <username> <token 1> <token 2>
$ ./keygenme32.elf Hexpresso 42 1337
error: Hexpresso is not a valid name
$ ./keygenme32.elf ABCDEFGHIJKLMNOP 42 1337
The username’s length has to be at least 16, and the tokens are two numbers. Let’s disassemble the file under IDA.
The main function firstly compares the username’s length with 15. If it is greater, we continue. A lot of functions are then called to finally have four numbers (two of them are the tokens, and I presume the other ones are generated thanks to the username). These four numbers are used in a check function, which can be written like that in Python:
def check(a1, a2, a3, a4): return a1 == (a3 ^ 0x31333337) and \ a2 == ((a4 & 0xFF) | (((a4 >> 24) & 0xFF) << 8) | ((((a4 & 0xFF00) >> 8) & 0xFF) << 16) | ((((a4 & 0xFF0000) >> 16) & 0xFF) << 24))
a1 and a2 are our tokens, and a3 & a4 are values we don’t know, but we can load the elf under gdb and set some breakpoints to find them. Once a3 and a4 have been found, we can compute the correct a1 and a2 (and therefore, the tokens for the corresponding name).
The aim of the challenge was to connect to a service (18.104.22.168:14549) which asked us the tokens for a given username (32 hex chars). We wrote a Python to script to automate the gdb session and find the tokens.
import socket, os s = socket.socket() s.connect(('22.214.171.124', 14549)) s.recv(1024) # Welcome message while True: username = s.recv(1024)[-33:-1] # Extract the username from the message print username gdbinit = """set pagination off set logging on file keygenme32.elf b *0x804a125 r username 123 456 x/x $ebp-0x30 x/x $ebp-0x2c c quit""".replace('username', username) open('.gdbinit', 'wb').write(gdbinit) os.system('gdb -q') log = open('log.txt', 'rb').read().split('\n') a3, a4 = eval(log[-3][-10:]), eval(log[-4][-10:]) token1 = a3 ^ 0x31333337 token2 = (a4 & 0xff) | ((a4 & 0xff00) << 16) | ((a4 & 0xff0000) >> 8) | ((a4 & 0xff000000) >> 8) s.send("%s %s\n" % (token1, token2)) print s.recv(4096)
The server asked us a lot of times to solve the problem, so we put everything in a While True and waited for the flag.