Insomni’hack 2013 – Armory level3

This challenge was the last level on the ARM platform. It was a crackme with a stripped binary including a basic anti-debugging trick. Sadly, only one team managed to complete this challenge before the end of Insomni’hack and another wasn’t far from what we discussed later.

Running the binary alone we can learn that two things should be provided: a username and a serial number. Maybe the two are linked, maybe not…

The check for the username is easily spotted using IDA and searching for cross-references to strcmp(). Also, the serial is XOR’d with this username.

[code language=”bash”]
.text:00008AE8 E4 01 9F E5 LDR R0, =aJackknife ; “jackknife”
.text:00008AEC 14 10 1B E5 LDR R1, [R11,#s2] ; s2
.text:00008AF0 68 FE FF EB BL strcmp
.text:00008AF4 00 30 A0 E1 MOV R3, R0
.text:00008AF8 00 00 53 E3 CMP R3, #0
.text:00008AFC 08 00 00 1A BNE loc_8b24

.text:00008B70 1C 20 1B E5 LDR R2, [R11,#var_1C]
.text:00008B74 10 30 1B E5 LDR R3, [R11,#var_10]
.text:00008B78 03 30 82 E0 ADD R3, R2, R3
.text:00008B7C 14 10 1B E5 LDR R1, [R11,#s2]
.text:00008B80 10 20 1B E5 LDR R2, [R11,#var_10]
.text:00008B84 02 20 81 E0 ADD R2, R1, R2
.text:00008B88 00 10 D2 E5 LDRB R1, [R2]
.text:00008B8C 18 00 1B E5 LDR R0, [R11,#s]
.text:00008B90 10 20 1B E5 LDR R2, [R11,#var_10]
.text:00008B94 02 20 80 E0 ADD R2, R0, R2
.text:00008B98 00 20 D2 E5 LDRB R2, [R2]
.text:00008B9C 02 20 21 E0 EOR R2, R1, R2
.text:00008BA0 72 20 EF E6 UXTB R2, R2
.text:00008BA4 00 20 C3 E5 STRB R2, [R3]
.text:00008BA8 10 30 1B E5 LDR R3, [R11,#var_10]
.text:00008BAC 01 30 83 E2 ADD R3, R3, #1
.text:00008BB0 10 30 0B E5 STR R3, [R11,#var_10]
[/code]

Next step: run the binary in GDB in order to see how the serial number is validated.

[code language=”bash”]
level3@sploitboard:~$ gdb ./level3
(gdb) r foo bar
Starting program: /home/level3/level3 foo bar
Ammo store
———-
Validating your credentials to download ammo for your weapons…

Program received signal SIGTRAP, Trace/breakpoint trap.
0xb6ec0bfc in raise () from /lib/arm-linux-gnueabihf/libc.so.6
[/code]

Wait what?!? You didn’t put any breakpoint and still a SIGTRAP is raised. Looking more closely we can see that the raise(3) function is called multiple times in the application so it seems that this is our anti-debugging trick.

[code language=”bash”]
Direction Type Address Text
——— —- ——- —-
Up p sub_889C+20 BL raise
Up p sub_88C8+18 BL raise
Up p sub_88F0+1C BL raise
Up p sub_891C+1C BL raise
Up p sub_8948+18 BL raise
Up p sub_8988+C BL raise
p sub_8A48+9C BL raise
Down p sub_8A48+F0 BL raise
Down p sub_8A48+188 BL raise
[/code]

We can also see that a signal handler is defined for SIGTRAP and SIGABRT and that this handler is incrementing a global variable:

[code language=”bash”]
.text:000089F4 LDR R3, =sig_handler
.text:000089F8 STR R3, [R11,#act]
.text:000089FC SUB R3, R11, #-act
.text:00008A00 MOV R0, #5 ; sig
.text:00008A04 MOV R1, R3 ; act
.text:00008A08 MOV R2, #0 ; oact
.text:00008A0C BL sigaction
.text:00008A10 SUB R3, R11, #-act
.text:00008A14 MOV R0, #6 ; sig
.text:00008A18 MOV R1, R3 ; act
.text:00008A1C MOV R2, #0 ; oact
.text:00008A20 BL

; sig_handler:
.text:000089BC 18 30 9F E5 LDR R3, =dword_10F7C
.text:000089C0 00 30 93 E5 LDR R3, [R3]
.text:000089C4 01 20 83 E2 ADD R2, R3, #1
.text:000089C8 0C 30 9F E5 LDR R3, =dword_10F7C
.text:000089CC 00 20 83 E5 STR R2, [R3]
[/code]

The first check that is done on the XOR’d serial number is using this counter so we might have to run this code to know this value without reversing the complete application. Using a breakpoint on raise(3) and the call method in GDB we can emulate the SIGTRAP without actually triggering it.

[code language=”bash”]
.text:00008BD4 1C 30 1B E5 LDR R3, [R11,#XOR_serial]
.text:00008BD8 00 30 D3 E5 LDRB R3, [R3]
.text:00008BDC 03 20 A0 E1 MOV R2, R3
.text:00008BE0 DC 30 9F E5 LDR R3, =dword_10F7C
.text:00008BE4 00 30 93 E5 LDR R3, [R3]
.text:00008BE8 03 30 82 E0 ADD R3, R2, R3
.text:00008BEC 73 30 EF E6 UXTB R3, R3
.text:00008BF0 A3 00 53 E3 CMP R3, #0xA3
[/code]

[code language=”bash”]
Breakpoint 1, 0xb6ec0bbc in raise () from /lib/arm-linux-gnueabihf/libc.so.6
(gdb) call (void)0x89a0(5)
$1 = 35232
(gdb) bt
#0 0xb6ec0bbc in raise () from /lib/arm-linux-gnueabihf/libc.so.6
#1 0x00008ae8 in ?? ()
#2 0x00008ae8 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) set $pc=0x8ae8
(gdb) c
Breakpoint 4, 0x00008be0 in ?? ()
(gdb) x /5i $pc
=> 0x8be0: ldr r3, [pc, #220] ; 0x8cc4
0x8be4: ldr r3, [r3]
0x8be8: add r3, r2, r3
0x8bec: uxtb r3, r3
0x8bf0: cmp r3, #163 ; 0xa3
(gdb) p *0x10f7c
$22 = 2
[/code]

This means that the XOR’d value added to 2 should be equal to 0xa3. Continuing this lenghty process, we can get all the characters of the serial number:

[code language=”bash”]
level3@sploitboard:~$ ./level3 jackknife `python -c ‘print “xcb”+”bxeaxe2aaaaa”‘`
Ammo store
———-
Validating your credentials to download ammo for your weapons…
36760a05c853e6a7444b6a3de2c100591e0ad9c0193c56ca562949f4f7342a808cead86e34f940fb88221403451345e36edddcce51934eb4ea64af7c27aa6650
[/code]