Skip to content

Commit

Permalink
End of part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
carstein committed Apr 24, 2020
1 parent 4db4123 commit 6ec4336
Showing 1 changed file with 104 additions and 26 deletions.
130 changes: 104 additions & 26 deletions fuzz.py
Expand Up @@ -3,6 +3,9 @@
# author: carstein <michal.melewski@gmail.com>

import argparse
import base64
import os
import os.path
import random
import sys
import signal
Expand All @@ -11,7 +14,6 @@

FLIP_RATIO = 0.01 # 1% ratio of bit flips
FLIP_ARRAY = [1, 2, 4, 8, 16, 32, 64, 128]

MAGIC_VALS = [
[0xFF],
[0x7F],
Expand All @@ -25,27 +27,55 @@
[0xFF, 0xFF, 0xFF, 0x7F], # 0x7FFFFFFF
]

def usage():
print("Usage: {} <valid_jpg>".format(sys.argv[0]))
# Gather unique crashes
crashes = {}

config = {
'file': 'mutated.jpg', # name of the target file
'target': '', # Location of program to execute
'corpus': '', # Initial corpus of files to mutate
'crashes_dir': 'crashes/', # Where to save crashes
'rounds': 100000, # How many fuzz iterations to run
'seed': None, # Seed for PRNG
}

def save_crashes():
print("Saving crashes...")
crash_dir = config['crashes_dir']

if not os.path.exists(crash_dir):
os.mkdir(crash_dir)

for ip, data in crashes.items():
filename = "crash.{:x}.jpg".format(ip)
with open(os.path.join(crash_dir, filename), "wb+") as fh:
fh.write(data)

print("{} unique crashes.".format(len(crashes)))

def absolute_address(ip, mappings):
for mapping in mappings:
if ip in mapping:
return ip-mapping.start

def execute_fuzz(dbg, data, counter):
cmd = ['exif/exif', 'data/mutated.jpg']
cmd = [config['target'], config['file']]
pid = debugger.child.createChild(cmd, no_stdout=True, env=None)
proc = dbg.addProcess(pid, True)
proc.cont()

try:
sig = dbg.waitSignals()
except:
return
event = dbg.waitProcessEvent()

if sig.signum == signal.SIGSEGV:
if event.signum == signal.SIGSEGV:
crash_ip = absolute_address(proc.getInstrPointer(), proc.readMappings())
if crash_ip not in crashes:
crashes[crash_ip] = data
proc.detach()
else:
proc.detach()
with open("crashes/crash.{}.jpg".format(counter), "wb+") as fh:
fh.write(data)

def create_new(data):
path = "data/mutated.jpg"
path = "mutated.jpg"
with open(path, "wb+") as fh:
fh.write(data)

Expand Down Expand Up @@ -76,31 +106,79 @@ def mutate(data):

return data

def get_bytes(filename):
with open(filename, "rb") as fh:
return bytearray(fh.read())
def get_corpus(path):
corpus = []

if os.path.isfile(path):
with open(path, "rb") as fh:
corpus.append(bytearray(fh.read()))
elif os.path.isdir(path):
for file in os.listdir(path):
if os.path.isfile(file):
with open(file, "rb") as fh:
corpus.append(bytearray(fh.read()))

return corpus


def create_config(args):
config['target'] = args.target
config['corpus'] = args.corpus

if args.rounds:
config['rounds'] = int(args.rounds)

if args.seed:
config['seed'] = base64.b64decode(seed)

def finish(sig, frame):
print("Finishing fuzz job.")
# Add function to dump all crashes
save_crashes()
sys.exit(1)

def main():
if len(sys.argv) < 2:
usage()
signal.signal(signal.SIGINT, finish)
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--target", help = "target program",
required=True)
parser.add_argument("-c", "--corpus", help = "corpus of files",
required=True)
parser.add_argument("-r", "--rounds", help = "number of rounds",
required=False)
parser.add_argument("-s", "--seed", help = "seed for PRNG",
required=False)
create_config(parser.parse_args())

corpus = get_corpus(config['corpus'])
dbg = debugger.PtraceDebugger()

# Seed the PRNG
if config['seed']:
initial_seed = config['seed']
else:
filename = sys.argv[1]
orig_data = get_bytes(filename)
dbg = debugger.PtraceDebugger()
initial_seed = os.urandom(24)

random.seed(initial_seed)
print("Starting new fuzzing run with seed {}".format(base64.b64encode(initial_seed).decode('utf-8')))

# Fuzz loop
for file in corpus:
counter = 0
while counter < 100000:
data = orig_data[:]
while counter < config['rounds']:
data = file[:]
mutated_data = mutate(data)
create_new(mutated_data) # new file
create_new(mutated_data)
execute_fuzz(dbg, mutated_data, counter)

if counter % 100 == 0:
print("Counter: {}\r".format(counter),file=sys.stderr, end='')

counter += 1

dbg.quit()
counter += 1

#cleanup
dbg.quit()
save_crashes()

if __name__ == "__main__":
sys.exit(main())

0 comments on commit 6ec4336

Please sign in to comment.