Data Execution Prevention

DEP is used to prevent executing code in memory/stack. This is done by marking the pages with read/write/execute flags. If a spot in memory is read/write, you can't just set rip to a spot in the memory and jump to it because it's no longer possible to do so.

Other exploitation techniques had to be developed in order for exploitation to be possible. ROP being one of them.

Return oriented programming

ROP is a technique commonly used to bypass DEP (Data Execution Prevention). The technique is commonly done by using snippets of code called gadgets and then chaining them together to form an exploit. These snippets of code have a 'ret' instruction at their end. A way to find ROP gadgets in a binary is to look at the assembly of the program. For example, run:

objdump -M intel -d binary | grep "ret"
pop rdi
ret

This snippet of gadget sets the rdi register to the next element in the stack. The best way to visualize this is by considering a scenario where a return address is overwritten. The stack layout around the return address would look something like this:

0x7fffffffedd8:     0x00000000004008e4 ; --[ Gadget ( pop rdi; ret )
0x7fffffffede0:     0x00007fffffffeeb8 ;--| Gadget Effect (rdi will equal this value)
0x7fffffffede8:     0x00007fffffffeeb8 ;--| Gadget Effect (rip will equal this value i.e. the ret instruction)
0x7fffffffedf0:     0x00007f0000262030 ; --[ rsp points here after gadget execution eg: exit

The important part is what you set in the next 2 values to be a syscall you would want to call. For example, you can call system and then '/bin/sh' from the libc using a ret2libc technique.

A little more advanced chain

Lets build a chain that manually executes a syscall. In this section we will execute following C code in rop chain,

execve("/bin/sh\x00", NULL, NULL)

Here's the assembly we write in rop

    pop rdi ; set this to "/bin/sh"
    ret
    pop rsi ; set this to NULL
    ret
    pop rdx ; set this to NULL
    ret
    pop rax ; set this to execve syscall 59
    ret
    syscall ; call execve
    ret

In the 64 bits stack, it would look something like this.

0x7fffffffedd8:     0x0000000000400af5 ; --[ Gadget ( pop rdi; ret )
0x7fffffffede0:     0x00007f00005b8d57 ; --| Gadget Effect (rdi will equal this value)
0x7fffffffede8:     0x0000000000400af7 ; --[ Gadget ( pop rsi; ret )
0x7fffffffedf0:     0x0000000000000000 ; --| Gadget Effect (rsi will equal this value)
0x7fffffffedf8:     0x0000000000400af9 ; --[ Gadget ( pop rdx; ret )
0x7fffffffee00:     0x0000000000000000 ;--| Gadget Effect (rdx will equal this value)
0x7fffffffee08:     0x0000000000400afb ;--[ Gadget ( pop rax; ret )
0x7fffffffee10:     0x000000000000003b ;--| Gadget Effect (rax will equal this value)
0x7fffffffee18:     0x0000000000400afd ;--[ Gadget ( syscall; ret )
0x7fffffffee20:     0x0000000000000000 ;--| Gadget Effect (rip will equal this value)
0x7fffffffee28:     0x0000000000000000 ;--[ rsp points here after gadget execution

Stack pivots

There's not always freedom to use things beyond the stack, for example there might be a stack cookie. The technique of pivoting the stack is common to do. For example,

pop rsp
ret

You set the value of the stack pointer such that you set it to an area where you have space to for example, later in the buffer or earlier where you might control. Then you do the usual rop-fu.

Some examples of stack pivots are :

'add/sub $rsp'

you add or subtract the stack point to move it up and down.

'leave; ret'

We know leave' is equivalent to

    mov rsp,rbp
    pop rbp

In scenarios where we have control over rbp, we can use a gadget like this to make more space with the gadget.

'xchg rsp'

This can be used to change exchange or swap the value of the stack pointer with any other registers.

How to find rop gadgets?

Commonly used tools for rop gadgets are ropper. There are other tools but ropper is the one I am most familiar with.

ropper file=binary find="pop"

The above code will atempt to find all the pop instruction in the assembly.

Alignment issues

One of the most common problems while doing a rop chain is stack alignment, where your program segfaults. This is because in a 64 bit system require your stack to be 16 bit aligned.

This is solved by added a ret instruction, because whenever a normal ret instruction, the stack pointer is incremented by 8 bytes (since it tries to index 8 bytes of return address)

TODO ROP tool in pwntools