Hack You CTF 2012 - Reverse 200

2 minute read

A zip file containing an ELF binary and Windows executable file was given to us. We need not care about the Windows executable as both the ELF binary and the Windows executable do the same things.

We run the program for the first time:

amon@Alyx:~/hackyou/rev200$ ./task2.bin
Welcome to the LoseYou lottery!
Generating random.....
Make your guess (number 0 or 1): 0
Fail... The number was 882298492
Try again.
Err, you shouldn't
amon@Alyx:~/hackyou/rev200$

Now run it through strace (here’s an extract):

write(1, "Welcome to the LoseYou lottery!n", 32Welcome to the LoseYou lottery!
) = 32
write(1, "Generating random", 17Generating random) = 17
nanosleep({1, 0}, 0xffd70fc4) = 0
write(1, ".", 1.) = 1
... more nanosleeps and write('.')s ...
write(1, "n", 1) = 1
time(NULL) = 1350644435
write(1, "Make your guess (number 0 or 1):"..., 33Make your guess (number 0 or 1): ) = 33
read(0, 31337"31337n", 1024) = 6
write(1, "Fail... The number was -65336549"..., 45Fail... The number was -653365492
Try again.
) = 45
nanosleep({2, 0}, 0xffd70fc4) = 0
write(1, "Err, you shouldn'tn", 19Err, you shouldn't) = 19
nanosleep({3, 0}, 0xffd70fc4) = 0
exit_group(0) = ?

The number is based on time(NULL), probably an srand around somewhere too. We could reverse the number generation algorithm, or we could just find out how the input test is done. First we made an objdump disassembly. After poking around in GDB, we discover the function calls not determined by static analysis.

80484d1: e8 aa 04 00 00 call 8048980 ; fgets()
80484d6: 83 c4 0c add $0xc,%esp
80484d9: 0f be 45 ee movsbl -0x12(%ebp),%eax
80484dd: 83 f8 31 cmp $0x31,%eax
80484e0: 0f 85 05 00 00 00 jne 80484eb
80484e6: e9 0a 00 00 00 jmp 80484f5
80484eb: b8 00 00 00 00 mov $0x0,%eax
80484f0: e9 05 00 00 00 jmp 80484fa
80484f5: b8 01 00 00 00 mov $0x1,%eax
80484fa: 89 45 e8 mov %eax,-0x18(%ebp)
80484fd: 8b 45 e8 mov -0x18(%ebp),%eax
8048500: 8b 4d f4 mov -0xc(%ebp),%ecx
8048503: 39 c8 cmp %ecx,%eax

We can see that %eax contains the user input and %ecx contains some validation value of some kind: the number. This can be verified by simply changing the register value in GDB.

(gdb) info reg
eax 0x0 0
ecx 0x215c6841 559704129
edx 0xf7fb63a4 -134519900
ebx 0xf7fb4ff4 -134524940
esp 0xffffd7a4 0xffffd7a4
ebp 0xffffd7e8 0xffffd7e8
esi 0x0 0
edi 0x0 0
eip 0x8048503 0x8048503
eflags 0x202 [ IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) set $eax = 0x215c6841
(gdb) c
Continuing.
You... you... win??? so lucky! Grab the flag:
::: oh_you_cheat3r :::
[Inferior 1 (process 7760) exited normally]
(gdb)

However, we want a more persistent way of obtaining the flag (for the fun of it) so we modify a few opcodes. Namely, at the following two locations:

804843a: e8 01 05 00 00 call 8048940 ; sleep
8048503: 39 c8 cmp %ecx,%eax

We just patch the call to sleep with NOP bytes (0x90), and the cmp to test %ecx with %ecx so the conditional will always run true.

Running this patched binary:

amon@Alyx:~/hackyou/rev200$ echo "" | ./task2.patched.bin
Welcome to the LoseYou lottery!
Generating random.....
Make your guess (number 0 or 1): You... you... win??? so lucky! Grab the flag:
::: oh_you_cheat3r :::
amon@Alyx:~/hackyou/rev200$

Leave a Comment