I am P1kachu

Security, cars, playing with fire.

HackCon 2016 - angry-reverser writeup (RE)

Binary: yolomolo.

I unfortunately couldn’t participate in this CTF, but some people who actually did sent me this exercise because they think it was a little bit too tricky to be solved by hand, and thought that angr could be helpful. Now that I have some time, I could actually take a look at it and indeed, angr does its job (the name was a big hint, maybe a little bit too much in my opinion).

I will not get into much details here, the binary is a 64-bit ELF executable with only a short main function that calls another one called GoHomeOrGoCrazy. The return value of this function determines if you have the right flag or not:

graph

It takes a lot of time for angr to solve it, but it’s always easier than doing it ourselves :)

Here is the script I used to solve this challenge:

import angr
import sys

# P1kachu 2016 - LSE
# HackCon 2016 - angry-reverser
# Took ~31 minutes on Intel Core i7-3770 CPU @ 3.40GHz (8 CPUs)
# Flag: HACKCON{VVhYS04ngrY}

p = angr.Project('yolomolo')

main        = 0x405a6f # Fail message to be printed
find        = 0x405aee # Win message printed
avoid       = (0x405af0, 0x405ab4) # First two ways to fail from main
crazy       = 0x400646 # Entry point of Crazy function

# Offset (from IDA) of 'FAIL' blocks in Crazy
fails = [0x2619, 0x288C, 0x2AF9, 0x2D68, 0x2FD5, 0x3245, 0x34B2,
         0x3724, 0x3996, 0x3C04, 0x3E73, 0x40E7, 0x4355, 0x45C9,
         0x4836, 0x4AA4, 0x4D15, 0x4F86, 0x51D1, 0x5408]

# Create blank state with $pc at &main
init = p.factory.blank_state(addr=main)

# Avoid blocks
avoid = list(avoid)
avoid += [(crazy + offst) for offst in fails] # Let's save RAM

print("Launching exploration")
pg = p.factory.path_group(init, threads=8)
ex = pg.explore(find=find, avoid=avoid)

# Get stdout
final = ex.found[0].state
print("Flag: {0}".format(final.posix.dumps(1)))

Flag: HACKCON{VVhYS04ngrY}

angry-reverser executable and script