Skip to content

Instantly share code, notes, and snippets.

@ljdelight
Created July 28, 2012 05:35
Show Gist options
  • Save ljdelight/3191941 to your computer and use it in GitHub Desktop.
Save ljdelight/3191941 to your computer and use it in GitHub Desktop.
Modify ODT archive for fuzzing penetration tests. Created for Udacity CS258 PS-4.
#
# Lucas Burson
# 26 June 2012
#
# This attempts to crash ODT (or docx) readers via a fuzzed input file.
# Since ODT is zipped, we need to extract the files and then write random bytes (keep valid CRC).
#
# TODO: Maybe we "shouldn't" destroy XML tags or attribute names... XSD/marshall would catch those
#
import os;
import zipfile;
import subprocess;
import random;
import time;
import shutil;
FUZZ_FACTOR = 400;
NUM_TESTS = 10;
SLEEP_DELAY = 1.8;
CRASH_DIR = "../crashed/"; # place failed runs here
RESOURCE_DIR = "../resources/"; # put all test files here, or in subdirs
APPLICATIONS_TO_RUN = [ ["/usr/bin/openoffice.org3", "-nologo", "-norestore" ] ];
# Return a list of files that are in the directory, searching recursively
def getFilesInDir( directory ):
fileList = [];
for root, subFolders, files in os.walk(directory):
for file in files:
fileList.append(os.path.join(root,file));
return fileList;
def runTest( testID, archiveFileList ):
fileChoice = random.choice(archiveFileList)
fuzzed_filename = "fuzzed_" + os.path.basename(fileChoice);
crashFilename = "%scrash_id%d_%s" % (CRASH_DIR, testID, os.path.basename(fileChoice));
tempDir = "./tmp/";
# extract the input ODT to the temporary directory
source = zipfile.ZipFile( fileChoice, "r" );
source.extractall(tempDir);
# get a list of files held in the directory
fileList = getFilesInDir(tempDir);
# choose a random file in the archive for fuzzing
file = open( random.choice(fileList), "r+b" );
buff = bytearray( file.read() );
# sometimes the selected file can be empty...
if ( len(buff) == 0 ):
buff = bytearray( "<foobar/>","UTF8");
numWrites = ( len(buff) / FUZZ_FACTOR ) or 1;
for _ in xrange(numWrites):
rbyte = random.randrange(256)
rn = random.randrange( len(buff) )
buff[rn] = "%c" % (rbyte)
# write the changes back to the file
file.write(buff);
# zip the files under a new name
result = zipfile.ZipFile( fuzzed_filename, "w" );
for name in source.namelist():
# Find the file in the tmp dir, and give it the same name (without tmp)
# write( localfile, archivename )
result.write( tempDir+name, name );
source.close();
result.close();
for app in APPLICATIONS_TO_RUN:
result = "";
additional="";
# try to open the fuzzed file
process = subprocess.Popen(app+[fuzzed_filename]);
time.sleep(SLEEP_DELAY);
if not process.poll():
process.terminate();
result = "Passed";
additional="";
else:
# crash! save the file
shutil.copyfile( fuzzed_filename, crashFilename );
result="FAILED";
additional = "savedFile='%s'" % (crashFilename);
# do some logging
print "Run_ID='%d'; res='%s'; zip='%s'; file='%s'; size='%dB'; fuzz='%dB'; app='%s'; %s" % \
(testID, result,fileChoice,file.name,len(buff),numWrites,app,additional);
# cleanup fuzzed file
os.remove(fuzzed_filename);
shutil.rmtree(tempDir);
def main():
archiveList = getFilesInDir( RESOURCE_DIR );
for i in xrange(NUM_TESTS):
runTest(i, archiveList);
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment