Payloads
The "Magic Gadget"
libc contains code to execve("/bin/sh") in several places. If you know the libc in use and its loaded base address (see ASLR), you can just jump there.
Reverse shells
ROP techniques
Tools:
Good to know:
callon x86-64 requires a 16-byte aligned stack. Not always an issue, but it can be. Pad your ROP chain.
Ret2CSU
TODO: Learn about this
Ret2ld-resolve
Tell me more Tell me not enough Tool
.got is populated by the linker (ld) on demand, when a .plt function is called for the first time.
Lookups are performed using some giant tables (JMPREL, SYMTAB, STRTAB), and string matching in these tables.
The top of .plt is a stub which calls dl-resolve, and takes an index into these tables as a parameter.
Write a fake
SYMTABandSTRTABsomewhere, containing an entry for"system"ROP into
dl-resolvewith a well-chosen table index (overflow the existingSTRTABinto our fake buffer)dl-resolvewill go findsystemand call it for us!
Danger Stack alignment is an issue, and system() relies on the stack being 16-byte aligned when it's called. If your chain doesn't work, try adding a ret; gadget to it for a different alignment.
Sigreturn Oriented Programming
If you can push to the stack and execute syscall 15, you can control all the registers at once. Neat.
Syscall cobbling
If you've got ROP control, maybe you can emulate a system call?
x86
Set $eax and find an int 0x80 instruction to lift off! Arguments are in $ebx, $ecx, $edx, $esi.
x86_64
Making a system call is as easy as setting $rax and executing the syscall instruction. Arguments are in $rdi, $rsi, $rdx.
32-bit syscalls are also available, see Evasion for more info about that.
Lesser-known syscalls
If there's a blocklist, here are some less obvious tricks:
arch_prctlcan be used for an arbitrary write (Tell me more)brkcan be used to find the address of the heap (Tell me more)
Register control
The ax registers which control syscall number also happen to be the return value registers in the SystemV calling convention. If you control a read() before your ROP chain, for example, it will return the number of bytes read. Send it 11 bytes and you've lined yourself up for execve()!
Alternatively, check out the Sigreturn syscall below to control all the registers!
Last updated