Created
July 28, 2012 05:35
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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