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:
call
on 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
SYMTAB
andSTRTAB
somewhere, containing an entry for"system"
ROP into
dl-resolve
with a well-chosen table index (overflow the existingSTRTAB
into our fake buffer)dl-resolve
will go findsystem
and 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_prctl
can be used for an arbitrary write (Tell me more)brk
can 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