This is my writeup for the fourth challenge in the PlaidCTF 2011 competition. The information for the challenge was:
“After breaking into the AED network, we stumbled across a router with custom software loaded. Intrigued by this discovery, we sent in a team and extracted the software.
Reverse engineer this strange code, and report back.”
The first step is obviously to determine the format of the file, which I simply used the “file” command for.
je@isis:~/ctf/PlaidCTF-2011/04-Here_There_Be_Dragons$ file f20b029ce96f0278322c0629b1265e1abd0e72cd.bin f20b029ce96f0278322c0629b1265e1abd0e72cd.bin: ELF 32-bit MSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, stripped
The file is a MIPS executable, and due to the following message within it it seems likely that it corresponds to a Cisco 3725 router image:
“Welcome to PPP IOS for C3725!”
Although this challenge certainly could be solved by pure static reversing, it will save a lot of time if we could actually run the code. Since I didn’t have a Cisco router laying around for the task, I used an emulator called Dynamips.
Dynamips has no builtin debugging facilities, but thanks to Sebastian Muñis and Alfredo Ortega of Groundwork Technologies there is a patch available that implements a GDB stub to allow for debugging with GDB, IDA Pro and other debuggers with support for the GDB remote protocol.
For the initial analysis of the binary I used IDA Pro, and could quickly pinpoint the code of interest. Using a combination of static reversing with IDA and debugging with GDB and Dynamips I could determine that the password is actually a numeric PIN, and once the correct PIN is entered, the password required to solve the challenge is decrypted and written to the terminal.
Note that we need a GDB with MIPS support to be able to use GDB for debugging. I used one compiler with mips-idt-elf as its target.
Debugging was extremely slow due to the fact that breakpoints did not seem to work. When a breakpoint was reached I got the following message in the emulator:
[[[ Virtual Breakpoint reached at PC=ADDR RA=ADDR]]] ...
It didn’t stop executing though.. So, I used GDB scripting to single-step to the instruction I wanted to break at instead:
while $pc != ADDR si end
To not have to step through the entire boot process I let it execute until the password prompt before breaking out into the debugger with ^C.
Using this technique I simply let it execute until the address where the PIN entered is compared with the expected PIN and extracted the correct PIN from there. Then I could boot up the image again, enter the correct PIN and get the password.
After solving the challenge I came up with a much faster technique, by simply patching the code where I want to break at with an eternal loop. Example below:
je@isis:~/ctf/PlaidCTF-2011/04-Here_There_Be_Dragons$ mips-idt-elf-gdb -q f20b029ce96f0278322c0629b1265e1abd0e72cd.bin (no debugging symbols found) (gdb) target remote 127.0.0.1:1234 Remote debugging using 127.0.0.1:1234 [New Thread 1] 0xbfc00000 in ?? () (gdb) set *0x800085e0 = 0x1000ffff (gdb) x/i 0x800085e0 0x800085e0: beq v1,v0,0x800085f0 0x800085e4: nop (gdb) set *0x800085e0 = 0x1000ffff (gdb) x/i 0x800085e0 0x800085e0: b 0x800085e0 0x800085e4: nop (gdb) c Continuing.
I now switch to the console where I’m running the emulator, and enter 12345 as my PIN:
Launching IOS image at 0x80008000... Welcome to PPP IOS for C3725! Secret: 12345
The emulator will now hang on my eternal loop, so I switch back to the debugger and press ^C:
Program received signal SIGTRAP, Trace/breakpoint trap. 0x800085d4 in ?? () (gdb) p/d $v0 $1 = 134217728 (gdb) p/d $v1 $2 = 12345
The v1 register contains the PIN I entered (12345), and v0 the expected one (134217728 = 0x8000000). Now I only need to enter the correct PIN to get the password.
je@isis:~/ctf/PlaidCTF-2011/04-Here_There_Be_Dragons$ dynamips -P 3725 f20b029ce96f0278322c0629b1265e1abd0e72cd.bin Cisco Router Simulation Platform (version 0.2.8-RC2-amd64) Copyright (c) 2005-2007 Christophe Fillot. Build date: Apr 23 2011 10:07:23 IOS image file: f20b029ce96f0278322c0629b1265e1abd0e72cd.bin ILT: loaded table "mips64j" from cache. ILT: loaded table "mips64e" from cache. ILT: loaded table "ppc32j" from cache. ILT: loaded table "ppc32e" from cache. CPU0: carved JIT exec zone of 64 Mb into 2048 pages of 32 Kb. NVRAM is empty, setting config register to 0x2142 C3725 instance 'default' (id 0): VM Status : 0 RAM size : 128 Mb NVRAM size : 128 Kb IOS image : f20b029ce96f0278322c0629b1265e1abd0e72cd.bin Loading ELF file 'f20b029ce96f0278322c0629b1265e1abd0e72cd.bin'... ELF entry point: 0x80008000 C3725 'default': starting simulation (CPU0 PC=0xffffffffbfc00000), JIT enabled. ROMMON emulation microcode. Launching IOS image at 0x80008000... Welcome to PPP IOS for C3725! Secret: 134217728 IsntCiscoGreat?