CSAW CTF 2013 | Reversing 400 : keygenme [Write Up]

nc 14549

In this challenge, we were given a 32-bit ELF keygenme in C++ which asks for a username and two «tokens».

$ ./keygenme32.elf
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 ( 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(('', 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
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.

Enjoy! \o/


Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s