Tuesday, October 22, 2013

[CTF] NcN Quals 2013: Level 3

This is the write-up for the Third level of NoNameCon CTF Quals 2013.

In a nutshell, a Linux reversing challenge where the goal is to get the secret key:
$ file ./level.elf
./level.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xb589d432799bf15343387fea63d4bdc00faa177c, not stripped
Running the executable, we are challenged to type a "password."
$ ./level.elf

|  >  Type to win, only what I want to read...
|  > 
Clicking any key, will end the program with an error message.
$ ./level.elf

|  >  Type to win, only what I want to read...
|  > 
The related executable code starts at 0x4010f3 with the getch() call.
   0x00000000004010f3 <+212>:   call   0x400fef <getch>
   0x00000000004010f8 <+217>:   movsx  eax,al
   0x00000000004010fb <+220>:   mov    DWORD PTR [rbp-0x4],eax
   0x00000000004010fe <+223>:   mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000401101 <+226>:   cdqe  
   0x0000000000401103 <+228>:   mov    eax,DWORD PTR [rax*4+0x6033a0]
   0x000000000040110a <+235>:   cmp    eax,DWORD PTR [rbp-0x4]
Breaking at the following "cmp" instruction:
(gdb) break *0x40110a
Breakpoint 1 at 0x40110a
(gdb) run
Starting program: /home/kroosec/Downloads/level.elf

|  >  Type to win, only what I want to read...
|  > 
Breakpoint 1, 0x000000000040110a in main ()
(gdb) p *((int *) ($rbp - 0x4))
$1 = 65
(gdb) p $rax
$2 = 32
Obviously, the cmp will be false as the char we typed A is not equal to the space (32 decimal in ASCII.)
To fix that:
(gdb) set *((int *) ($rbp - 0x4)) = 32
Then we continue, again we come back
(gdb) c
Breakpoint 1, 0x000000000040110a in main ()
(gdb) p $rax
$3 = 83
Again, we return to the same place, (getch() call followed by cmp.)
This time the character is 'S', and to fix our erroneous guess:
(gdb) set *((int *) ($rbp - 0x4)) = 83
This is the main routine of the program. A loop that reads stdin character by character and compares them to the password's. In a normal situation, where the password is a some long string, we would have needed a brute-forcing program, but in this case, the string is pretty short and obvious (my 2nd guess, after finding the 2nd R ;))
$ echo ' SURPRISE!' | ./level.elf

|  >  Type to win, only what I want to read...
|  >  **********
|  -> Congratulations! The key is:
|  9e0d399e83e7c50c615361506a294eca22dc49bfddd90eb7a831e90e9e1bf2fb