> For the complete documentation index, see [llms.txt](https://ret2basic.gitbook.io/ctfnote/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ret2basic.gitbook.io/ctfnote/pwn/linux-exploitation/rop/ret2syscall.md).

# ret2syscall

## Theory

If the binary itself contains `int 0x80` (x86) or `syscall` (x86\_64) as well as necessary ROP gadgets, you might want to try **ret2syscall** to get a shell. To find such gadgets, use **ROPgadget** or **Ropper**. With this method, you simply build an ROP chain to set all relevant registers to some proper state and call `int 0x80` (x86) or `syscall` (x86\_64) when everything is ready. This idea is the same as an `execve()` shellcode.

Below is a quick cheat sheet. This cheat sheet provides a general idea of how ret2syscall is exploited, but it is definitely **NOT** the only way of doing it. If any gadget is missing from the binary, use your creativity to build equivalent ROP chains.

## 32-bit ret2syscall

### **Calling Convention**

* syscall number: `$eax`
* 1st parameter: `$ebx`
* 2nd parameter: `$ecx`
* 3rd parameter: `$edx`
* 4th parameter: `$esi`
* 5th parameter: `$edi`
* 6th parameter: `$ebp`
* call `int 0x80` when everything is ready.

### **Calling `execve("/bin/sh", 0, 0)`**

1. Set `$eax` to `0xb`
   * `ROPgadget --binary vuln --only "pop|ret" | grep eax`
2. Set `$ebx` to the address of the string `"/bin/sh"`
   * `ROPgadget --binary vuln --only "pop|ret" | grep ebx`
   * `ROPgadget --binary vuln --string "/bin/sh"`
3. Set `$ecx` to `0`
   * `ROPgadget --binary vuln --only "pop|ret" | grep ecx`
4. Set `$edx` to `0`
   * `ROPgadget --binary vuln --only "pop|ret" | grep edx`
5. Call `int 0x80` (opcode for syscall on x86)
   * `ROPgadget --binary vuln --only "int"`

## 64-bit ret2syscall

### **Calling Convention**

* syscall number: `$rax`
* 1st parameter: `$rdi`
* 2nd parameter: `$rsi`
* 3rd parameter: `$rdx`
* 4th parameter: `$r10`
* 5th parameter: `$r8`
* 6th parameter: `$r9`
* call `syscall` when everything is ready.

**Note:** If there exists more arguments, the extra ones will be stored on the stack.

### **Calling `execve("/bin/sh", 0, 0)`**

1. Set `$rax` to `0x3b`
   * `ROPgadget --binary vuln --only "pop|ret" | grep rax`
2. Set `$rdi` to the address of the string `"/bin/sh"`
   * `ROPgadget --binary vuln --only "pop|ret" | grep rdi`
   * `ROPgadget --binary vuln --string "/bin/sh"`
3. Set `$rsi` to `0`
   * `ROPgadget --binary vuln --only "pop|ret" | grep rsi`
4. Set `$rdx` to `0`
   * `ROPgadget --binary vuln --only "pop|ret" | grep rdx`
5. Find `syscall`
   * `ROPgadget --binary vuln --only "syscall"`

## Nuance

Oftentimes, the binary does not contain the string `"/bin/sh"`. If that is the case, we should pass `"/bin/sh"` to the `.bss` section before exploiting ret2syscall. The address of `.bss` can be easily found using Pwntools: `bss = elf.bss()`. The binary may contain some input function, such as `gets()`. We can utilize input functions such as `gets()` for initializing a STDIN session and then input the string `"/bin/sh"` in this STDIN session.
