def main(): # first lets create the base directorty to keep all temporary data try: shutil.rmtree(config.BASETMP) except OSError: pass if os.path.isdir(config.BASETMP) == False: os.mkdir(config.BASETMP) check_env() ## parse the arguments ######### parser = argparse.ArgumentParser(description='VUzzer options') parser.add_argument( '-s', '--sut', help='SUT commandline with %s as placeholder for SUT input', required=True) parser.add_argument('-i', '--inputd', help='seed input directory (relative path)', required=True) parser.add_argument( '-w', '--weight', help= 'path of the pickle file(s) for BB wieghts (separated by comma, in case there are two) ', required=True) parser.add_argument( '-n', '--name', help= 'Path of the pickle file(s) containing strings from CMP inst (separated by comma if there are two).', required=True) parser.add_argument( '-l', '--libnum', help= 'Nunber of binaries to monitor (only application or used libraries)', required=False, default=1) parser.add_argument( '-o', '--offsets', help= 'base-address of application and library (if used), separated by comma', required=False, default='0x0000000000000000') parser.add_argument('-b', '--libname', help='library name to monitor', required=False, default='') args = parser.parse_args() config.SUT = args.sut config.INITIALD = os.path.join(config.INITIALD, args.inputd) config.LIBNUM = int(args.libnum) config.LIBTOMONITOR = args.libname config.LIBPICKLE = [w for w in args.weight.split(',')] config.NAMESPICKLE = [n for n in args.name.split(',')] config.LIBOFFSETS = [o for o in args.offsets.split(',')] config.LIBS = args.libname #ih=config.BBCMD.index("LIBS=") # this is just to find the index of the placeholder in BBCMD list to replace it with the libname ih = config.BBCMD.index( "#" ) # this is just to find the index of the placeholder in BBCMD list to replace it with the libname #config.BBCMD[ih]="LIBS=%s" % args.libname config.BBCMD[ih] = args.libname ################################### config.minLength = get_min_file(config.INITIALD) try: shutil.rmtree(config.KEEPD) except OSError: pass os.mkdir(config.KEEPD) try: os.mkdir("outd") except OSError: pass try: os.mkdir("outd/crashInputs") except OSError: gau.emptyDir("outd/crashInputs") crashHash = [] try: os.mkdir(config.SPECIAL) except OSError: gau.emptyDir(config.SPECIAL) try: os.mkdir(config.INTER) except OSError: gau.emptyDir(config.INTER) ############################################################################# #let us get the base address of the main executable. ifiles = os.listdir(config.INITIALD) for fl in ifiles: tfl = os.path.join(config.INITIALD, fl) try: f = open(tfl, 'r') f.close() except: gau.die("can not open our own input %s!" % (tfl, )) (ibbs, iretc) = execute(tfl) break # we just want to run the executable once to get its load address imgOffFd = open("imageOffset.txt", 'r') for ln in imgOffFd: if "Main:" in ln: lst = ln.split() break config.LIBOFFSETS[0] = lst[1][:] imgOffFd.close() ############################################################################# ###### open names pickle files gau.prepareBBOffsets() # lets initialize the BBFORPRUNE list from thie cALLBB set. if len(config.cALLBB) > 0: config.BBFORPRUNE = list(config.cALLBB) else: print "[*]: cALLBB is not initialized. something is wrong!!\n" system.exit() if config.PTMODE: pt = simplept.simplept() else: pt = None if config.ERRORBBON == True: gbb, bbb = dry_run() else: gbb = 0 # gau.die("dry run over..") import timing #selftest() noprogress = 0 currentfit = 0 lastfit = 0 config.CRASHIN.clear() stat = open("stats.log", 'w') stat.write("**** Fuzzing started at: %s ****\n" % (datetime.now().isoformat('+'), )) stat.write("**** Initial BB for seed inputs: %d ****\n" % (gbb, )) stat.flush() os.fsync(stat.fileno()) stat.write( "Genaration\t MINfit\t MAXfit\t AVGfit MINlen\t Maxlen\t AVGlen\t #BB\t AppCov\t AllCov\n" ) stat.flush() os.fsync(stat.fileno()) starttime = time.clock() allnodes = set() alledges = set() try: shutil.rmtree(config.INPUTD) except OSError: pass shutil.copytree(config.INITIALD, config.INPUTD) # fisrt we get taint of the intial inputs get_taint(config.INITIALD, 1) #print "MOst common offsets and values:", config.MOSTCOMMON #print "Base address: %s"%config.LIBOFFSETS[0] #raw_input("Press enter to continue..") config.MOSTCOMFLAG = True crashhappend = False filest = os.listdir(config.INPUTD) filenum = len(filest) if filenum < config.POPSIZE: gau.create_files(config.POPSIZE - filenum) if len(os.listdir(config.INPUTD)) != config.POPSIZE: gau.die("something went wrong. number of files is not right!") efd = open(config.ERRORS, "w") gau.prepareBBOffsets() writecache = True genran = 0 bbslide = 100 # this is used to call run_error_BB() functions. currently, i have decided to not call it thus a long wait keepslide = 3 keepfilenum = config.BESTP config.SEENBB.clear() #initialize set of BB seen so far, which is 0 del config.SPECIALENTRY[:] todelete = set( ) #temp set to keep file names that will be deleted in the special folder while True: #print "[**] Generation %d\n***********"%(genran,) del config.TEMPTRACE[:] del config.BBSEENVECTOR[:] SPECIALCHANGED = False # this is set when a config.SPECIAL gets at least one new input per generation. config.TMPBBINFO.clear() config.TMPBBINFO.update(config.PREVBBINFO) fitnes = dict() execs = 0 config.cPERGENBB.clear() config.GOTSTUCK = False if config.ERRORBBON == True: if genran > config.GENNUM / 5: bbslide = max(bbslide, config.GENNUM / 20) keepslide = max(keepslide, config.GENNUM / 100) keepfilenum = keepfilenum / 2 if 0 < genran < config.GENNUM / 5 and genran % keepslide == 0: copy_files(config.INPUTD, config.KEEPD, keepfilenum) #lets find out some of the error handling BBs if genran > 2000 and genran % bbslide == 0: # large number 2000 is to prevent not starting intermediate error BB cal. it is expensive and I am working on it. stat.write("\n**** Error BB cal started ****\n") stat.flush() os.fsync(stat.fileno()) run_error_bb(pt) copy_files(config.KEEPD, config.INPUTD, len(os.listdir(config.KEEPD)) * 1 / 10) #copy_files(config.INITIALD,config.INPUTD,1) files = os.listdir(config.INPUTD) per_gen_fnum = 0 for fl in files: per_gen_fnum += 1 tfl = os.path.join(config.INPUTD, fl) iln = os.path.getsize(tfl) args = (config.SUT % tfl).split(' ') progname = os.path.basename(args[0]) (bbs, retc) = execute(tfl) if per_gen_fnum % 10 == 0: print "[**] Gen: %d. Executed %d of %d.**" % ( genran, per_gen_fnum, config.POPSIZE) if config.BBWEIGHT == True: fitnes[fl] = gau.fitnesCal2(bbs, fl, iln) else: fitnes[fl] = gau.fitnesNoWeight(bbs, fl, iln) #raw_input() execs += 1 #let us prune the inputs(if at all), whose trace is subset of the new input just got executed. SPECIALADDED = False if config.GOTSPECIAL == True: SPECIALCHANGED = True SPECIALADDED = True todelete.clear() form_bitvector2(bbs, fl, config.BBFORPRUNE, config.SPECIALBITVECTORS) shutil.copy(tfl, config.SPECIAL) config.SPECIALENTRY.append(fl) for sfl, bitv in config.SPECIALBITVECTORS.iteritems(): if sfl == fl: continue if (config.SPECIALBITVECTORS[fl] & bitv) == bitv: tpath = os.path.join(config.SPECIAL, sfl) os.remove(tpath) todelete.add(sfl) config.SPECIALENTRY.remove(sfl) if sfl in config.TAINTMAP: del config.TAINTMAP[sfl] for ele in todelete: del config.SPECIALBITVECTORS[ele] if retc < 0 and retc != -2: #print "[*]Error code is %d"%(retc,) efd.write("%s: %d\n" % (tfl, retc)) efd.flush() os.fsync(efd) tmpHash = sha1OfFile(config.CRASHFILE) if tmpHash not in crashHash: crashHash.append(tmpHash) tnow = datetime.now().isoformat().replace(":", "-") nf = "%s-%s.%s" % (progname, tnow, gau.splitFilename(fl)[1]) npath = os.path.join("outd/crashInputs", nf) shutil.copyfile(tfl, npath) if SPECIALADDED == False: shutil.copy(tfl, config.SPECIAL) config.CRASHIN.add(fl) if config.STOPONCRASH == True: #efd.close() crashhappend = True break fitscore = [v for k, v in fitnes.items()] maxfit = max(fitscore) avefit = sum(fitscore) / len(fitscore) mnlen, mxlen, avlen = gau.getFileMinMax(config.INPUTD) print "[*] Done with all input in Gen, starting SPECIAL. \n" appcov, allcov = gau.calculateCov() tnow = datetime.now().isoformat().replace(":", "-") #stat.write("\t%d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %s\n"%(genran,min(fitscore),maxfit,avefit,mnlen,mxlen,avlen,len(config.cPERGENBB),appcov,allcov,tnow)) stat.write("\t%d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %s\n" % (genran, min(fitscore), maxfit, avefit, mnlen, mxlen, avlen, len(config.SEENBB), appcov, allcov, tnow)) stat.flush() os.fsync(stat.fileno()) print "[*] Wrote to stat.log\n" if crashhappend == True: break #lets find out some of the error handling BBs #if genran >20 and genran%5==0: # run_error_bb(pt) genran += 1 #this part is to get initial fitness that will be used to determine if fuzzer got stuck. lastfit = currentfit #currentfit=maxfit currentfit = len(config.SEENBB) if currentfit == lastfit: #lastfit-config.FITMARGIN < currentfit < lastfit+config.FITMARGIN: noprogress += 1 else: noprogress = 0 if noprogress > 20: config.GOTSTUCK = True stat.write("Heavy mutate happens now..\n") noprogress = 0 if (genran >= config.GENNUM) and (config.STOPOVERGENNUM == True): break if len(os.listdir(config.SPECIAL)) > 0 and SPECIALCHANGED == True: if len(os.listdir(config.SPECIAL)) < config.NEWTAINTFILES: get_taint(config.SPECIAL) else: try: os.mkdir(config.TAINTTMP) except OSError: gau.emptyDir(config.TAINTTMP) if conditional_copy_files(config.SPECIAL, config.TAINTTMP, config.NEWTAINTFILES) == 0: get_taint(config.TAINTTMP) #print "MOst common offsets and values:", config.MOSTCOMMON #gg=raw_input("press any key to continue..") print "[*] Going for new generation creation.\n" gau.createNextGeneration3(fitnes, genran) #raw_input("press any key...") efd.close() stat.close() libfd_mm.close() libfd.close() endtime = time.clock() print "[**] Totol time %f sec." % (endtime - starttime, ) print "[**] Fuzzing done. Check %s to see if there were crashes.." % ( config.ERRORS, )
def main(): # first lets create the base directorty to keep all temporary data try: shutil.rmtree(config.BASETMP) except OSError: pass if os.path.isdir(config.BASETMP) == False: os.mkdir(config.BASETMP) check_env() ## parse the arguments ######### parser = argparse.ArgumentParser(description='VUzzer options') parser.add_argument('-s', '--sut', help='SUT commandline', required=True) parser.add_argument('-i', '--inputd', help='seed input directory (relative path)', required=True) parser.add_argument( '-w', '--weight', help= 'path of the pickle file(s) for BB wieghts (separated by comma, in case there are two) ', required=True) parser.add_argument( '-n', '--name', help= 'Path of the pickle file(s) containing strings from CMP inst (separated by comma if there are two).', required=True) parser.add_argument( '-l', '--libnum', help= 'Nunber of binaries to monitor (only application or used libraries)', required=False, default=1) parser.add_argument( '-o', '--offsets', help= 'base-address of application and library (if used), separated by comma', required=False, default='0x00000000') parser.add_argument('-b', '--libname', help='library name to monitor', required=False, default='') args = parser.parse_args() config.SUT = args.sut config.INITIALD = os.path.join(config.INITIALD, args.inputd) config.LIBNUM = int(args.libnum) config.LIBTOMONITOR = args.libname config.LIBPICKLE = [w for w in args.weight.split(',')] config.NAMESPICKLE = [n for n in args.name.split(',')] config.LIBOFFSETS = [o for o in args.offsets.split(',')] ih = config.PINCMD.index("#") config.PINCMD[ih] = args.libname ################################### config.minLength = get_min_file(config.INITIALD) try: shutil.rmtree(config.KEEPD) except OSError: pass os.mkdir(config.KEEPD) try: os.mkdir("outd") except OSError: pass try: os.mkdir("outd/crashInputs") except OSError: gau.emptyDir("outd/crashInputs") try: os.mkdir("outd/hangs") except OSError: gau.emptyDir("outd/hangs") try: os.mkdir("outd/temp") except: gau.emptyDir("outd/temp") crashHash = [] try: os.mkdir(config.SPECIAL) except OSError: gau.emptyDir(config.SPECIAL) try: os.mkdir(config.INTER) except OSError: gau.emptyDir(config.INTER) ###### open names pickle files gau.prepareBBOffsets() if len(config.cALLBB) > 0: config.BBFORPRUNE = list(config.cALLBB) else: print "[*]: cALLBB is not initialized. something is wrong!!\n" system.exit() if config.PTMODE: pt = simplept.simplept() else: pt = None if config.ERRORBBON == True: gbb, bbb = dry_run() else: gbb = 0 # gau.die("dry run over..") import timing #selftest() noprogress = 0 currentfit = 0 lastfit = 0 config.CRASHIN.clear() stat = open("stats.log", 'w') stat.write("**** Fuzzing started at: %s ****\n" % (datetime.now().isoformat('+'), )) stat.write("**** Initial BB for seed inputs: %d ****\n" % (gbb, )) stat.flush() os.fsync(stat.fileno()) stat.write( "Genaration\t MINfit\t MAXfit\t AVGfit MINlen\t Maxlen\t AVGlen\t #BB\t AppCov\t AllCov\n" ) stat.flush() os.fsync(stat.fileno()) starttime = time.clock() allnodes = set() alledges = set() try: shutil.rmtree(config.INPUTD) #shutil.rmtree(config.BUGD) except OSError: pass shutil.copytree(config.INITIALD, config.INPUTD) # fisrt we get taint of the intial inputs get_taint(config.INITIALD, 1) print "MOst common offsets and values:", config.MOSTCOMMON #gg=raw_input("press enter to continue..") #gau_new.initialFuzz() config.MOSTCOMFLAG = True crashhappend = False filest = os.listdir(config.INPUTD) filenum = len(filest) if filenum < config.POPSIZE: gau.create_files(config.POPSIZE - filenum) if len(os.listdir(config.INPUTD)) != config.POPSIZE: gau.die("something went wrong. number of files is not right!") efd = open(config.ERRORS, "w") gau.prepareBBOffsets() writecache = True genran = 0 bbslide = 10 # this is used to call run_error_BB() functions keepslide = 3 keepfilenum = config.BESTP config.SEENBB.clear() del config.SPECIALENTRY[:] todelete = set() inputs_new_run = [] while True: print "[**] Generation %d\n***********" % (genran, ) #del config.SPECIALENTRY[:] del config.TEMPTRACE[:] del config.BBSEENVECTOR[:] #config.SEENBB.clear() SPECIALCHANGED = False # this is set when at least one new input is added to the config.SPECIAL folder. config.TMPBBINFO.clear() config.TMPBBINFO.update(config.PREVBBINFO) fitnes = dict() execs = 0 config.cPERGENBB.clear() config.GOTSTUCK = False if config.ERRORBBON == True: if genran > config.GENNUM / 5: bbslide = max(bbslide, config.GENNUM / 20) keepslide = max(keepslide, config.GENNUM / 100) keepfilenum = keepfilenum / 2 #config.cPERGENBB.clear() #config.GOTSTUCK=False #if 0< genran < config.GENNUM/5 and genran%keepslide == 0: # copy_files(config.INPUTD,config.KEEPD,keepfilenum) #lets find out some of the error handling BBs if genran > 20 and genran % bbslide == 0: stat.write("\n**** Error BB cal started ****\n") stat.flush() os.fsync(stat.fileno()) #run_error_bb(pt) #copy_files(config.KEEPD,config.INPUTD,len(os.listdir(config.KEEPD))*1/10) #copy_files(config.INITIALD,config.INPUTD,1) if genran == 1 or genran % 10 == 0: #f_log = open('out.txt', 'a') #print >> f_log, genran, inputs_new_run #f_log.close() gau.createBufferOverflowinputs(inputs_new_run) gau.createIntegerOverflowInputs(inputs_new_run) #gau.createMallocInputs(inputs_new_run) inputs_new_run = [] files = os.listdir(config.BUGD) for fl in files: tfl = os.path.join(config.BUGD, fl) iln = os.path.getsize(tfl) args = (config.SUT % tfl).split(' ') progname = os.path.basename(args[0]) #print '' #print 'Input file sha1:', sha1OfFile(tfl) #print 'Going to call:', ' '.join(args) retc = execute_without_analysis(tfl) if retc == None: npath = os.path.join("outd/hangs", fl) shutil.copyfile(tfl, npath) os.remove(tfl) continue #raw_input() execs += 1 #print "** %s: %d"%(fl,fitnes[fl]) if retc < 0 and retc != -2: shutil.copy(tfl, config.INPUTD) files = os.listdir(config.INPUTD) for fl in files: tfl = os.path.join(config.INPUTD, fl) iln = os.path.getsize(tfl) args = (config.SUT % tfl).split(' ') progname = os.path.basename(args[0]) #print '' #print 'Input file sha1:', sha1OfFile(tfl) #print 'Going to call:', ' '.join(args) (bbs, retc) = execute(tfl) if os.path.exists(os.path.join("outd/hangs", fl)): continue if config.BBWEIGHT == True: fitnes[fl] = gau.fitnesCal2(bbs, fl, iln) else: fitnes[fl] = gau.fitnesNoWeight(bbs, fl, iln) #raw_input() execs += 1 SPECIALADDED = False if config.GOTSPECIAL == True: #spinputs=os.listdir("outd/hangs") #if fl in spinputs: # break SPECIALADDED = True SPECIALCHANGED = True todelete.clear() form_bitvector2(bbs, fl, config.BBFORPRUNE, config.SPECIALBITVECTORS) shutil.copy(tfl, config.SPECIAL) config.SPECIALENTRY.append(fl) inputs_new_run.append(fl) for sfl, bitv in config.SPECIALBITVECTORS.iteritems(): if sfl == fl: continue if (config.SPECIALBITVECTORS[fl] & bitv) == bitv: tpath = os.path.join(config.SPECIAL, sfl) os.remove(tpath) todelete.add(sfl) config.SPECIALENTRY.remove(sfl) if sfl in config.TAINTMAP: del config.TAINTMAP[sfl] del config.ANALYSIS_MAP[sfl] if sfl in inputs_new_run: inputs_new_run.remove(sfl) for ele in todelete: del config.SPECIALBITVECTORS[ele] #print "** %s: %d"%(fl,fitnes[fl]) if retc < 0 and retc != -2: print "[*]Error code is %d" % (retc, ) tmpHash = sha1OfFile(config.CRASHFILE) efd.write("%s: %d\n" % (tfl, retc)) efd.flush() os.fsync(efd) config.err_in.append(fl) tnow = datetime.now().isoformat().replace(":", "-") nf = "%s-%s.%s" % (progname, tnow, fl) npath = os.path.join("outd/temp", nf) shutil.copyfile(tfl, npath) if tmpHash not in crashHash: crashHash.append(tmpHash) tnow = datetime.now().isoformat().replace(":", "-") nf = "%s-%s.%s" % (progname, tnow, gau.splitFilename(fl)[1]) npath = os.path.join("outd/crashInputs", nf) shutil.copyfile(tfl, npath) if SPECIALADDED == False: shutil.copy(tfl, config.SPECIAL) #config.SPECIALENTRY.append(fl) #SPECIALADDED=False config.CRASHIN.add(fl) if config.STOPONCRASH == True: #efd.close() crashhappend = True break fitscore = [v for k, v in fitnes.items()] maxfit = max(fitscore) avefit = sum(fitscore) / len(fitscore) mnlen, mxlen, avlen = gau.getFileMinMax(config.INPUTD) print "[*] Done with all input in Gen, starting SPECIAL. \n" #### copy special inputs in SPECIAL directory and update coverage info ### appcov, allcov = gau.calculateCov() tnow = datetime.now().isoformat().replace(":", "-") stat.write( "\t%d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %s\t %s\n" % (genran, min(fitscore), maxfit, avefit, mnlen, mxlen, avlen, len(config.SEENBB), appcov, allcov, config.NUMINPUTS, config.fname, tnow)) stat.flush() os.fsync(stat.fileno()) print "[*] Wrote to stat.log\n" if crashhappend == True: break genran += 1 #this part is to get initial fitness that will be used to determine if fuzzer got stuck. lastfit = currentfit #currentfit=maxfit currentfit = len(config.SEENBB) if currentfit == lastfit: #lastfit-config.FITMARGIN < currentfit < lastfit+config.FITMARGIN: noprogress += 1 else: noprogress = 0 if noprogress > 20: config.GOTSTUCK = True stat.write("Heavy mutate happens now..\n") noprogress = 0 if (genran >= config.GENNUM) and (config.STOPOVERGENNUM == True): break if len(os.listdir(config.SPECIAL)) > 0 and SPECIALCHANGED == True: if len(os.listdir(config.SPECIAL)) < config.NEWTAINTFILES: get_taint(config.SPECIAL) else: try: os.mkdir(config.TAINTTMP) except OSError: gau.emptyDir(config.TAINTTMP) if conditional_copy_files(config.SPECIAL, config.TAINTTMP, config.NEWTAINTFILES) == 0: get_taint(config.TAINTTMP) #print "MOst common offsets and values:", config.MOSTCOMMON #gg=raw_input("press any key to continue..") print "[*] Going for new generation creation.\n" gau.createNextGeneration3(fitnes, genran) #raw_input("press any key...") efd.close() stat.close() libfd_mm.close() libfd.close() endtime = time.clock() print "[**] Totol time %f sec." % (endtime - starttime, ) print "[**] Fuzzing done. Check %s to see if there were crashes.." % ( config.ERRORS, )
def main(): banner() # first lets create the base directorty to keep all temporary data try: shutil.rmtree(config.BASETMP) except OSError: pass if os.path.isdir(config.BASETMP) == False: os.mkdir(config.BASETMP) check_env() ## parse the arguments ######### parser = argparse.ArgumentParser(description='VUzzer options') parser.add_argument('-s', '--sut', help='SUT commandline', required=True) parser.add_argument( '-i', '--inputd', help='seed input directory (relative path)', required=True) parser.add_argument( '-w', '--weight', help='path of the pickle file(s) for BB wieghts (separated by comma, in case there are two) ', required=True) parser.add_argument( '-n', '--name', help='Path of the pickle file(s) containing strings from CMP inst (separated by comma if there are two).', required=True) parser.add_argument( '-l', '--libnum', help='Nunber of binaries to monitor (only application or used libraries)', required=False, default=1) parser.add_argument('-o', '--offsets', help='base-address of application and library (if used), separated by comma', required=False, default='0x00000000') parser.add_argument( '-b', '--libname', help='library name to monitor', required=False, default='#') args = parser.parse_args() config.SUT = args.sut config.INITIALD = os.path.join(config.INITIALD, args.inputd) config.LIBNUM = int(args.libnum) config.LIBTOMONITOR = args.libname config.LIBPICKLE = [w for w in args.weight.split(',')] config.NAMESPICKLE = [n for n in args.name.split(',')] config.LIBOFFSETS = [o for o in args.offsets.split(',')] config.LIBS = args.libname # this is just to find the index of the placeholder in BBCMD list to replace it with the libname ih = config.BBCMD.index("LIBS=") config.BBCMD[ih] = "LIBS=%s" % args.libname gau.log_print( "[*] Checking tmps files" ) if config.CLEARSPECIALOUTPUT: gau.delete_special_out_file(config.SPECIALOUTPUT) if path.exists("vuzzerRun.log"): os.remove("vuzzerRun.log") gau.log_print( "[*] Checking directories" ) if config.USEPATTERNDETECTION == True: initPatterns() ################################### afl.clearDir() config.minLength = get_min_file(config.INITIALD) try: shutil.rmtree(config.KEEPD) except OSError: pass os.mkdir(config.KEEPD) try: os.mkdir("outd") except OSError: pass try: os.mkdir("outd/crashInputs") except OSError: gau.emptyDir("outd/crashInputs") crashHash = [] try: os.mkdir(config.SPECIAL) except OSError: gau.emptyDir(config.SPECIAL) try: os.mkdir(config.INTER) except OSError: gau.emptyDir(config.INTER) gau.log_print( "[*] Checking executable base address" ) ############################################################################# # let us get the base address of the main executable. ifiles = os.listdir(config.INITIALD) for fl in ifiles: tfl = os.path.join(config.INITIALD, fl) try: f = open(tfl, 'r') f.close() except: gau.die("[-] Can not open our own input %s !" % (tfl)) (ibbs, iretc) = execute(tfl) if iretc != 128: # 0 gau.die("[-] Can't run the target program '%s' !" % (os.path.basename(config.SUT.replace(" ","").replace("%s","")))) break # we just want to run the executable once to get its load address imgOffFd = open("imageOffset.txt", 'r') for ln in imgOffFd: if "Main:" in ln: lst = ln.split() break config.LIBOFFSETS[0] = lst[1][:] imgOffFd.close() if config.LIBTOMONITOR != '' and config.LIBTOMONITOR != '#': gau.log_print("[+] Lib %s is at 0x%x" % (config.LIBTOMONITOR, int(config.LIBOFFSETS[1], 0))) gau.log_print( "[*] Checking pickles" ) ############################################################################# # open names pickle files gau.prepareBBOffsets() # lets initialize the BBFORPRUNE list from thie cALLBB set. if len(config.cALLBB) > 0: config.BBFORPRUNE = list(config.cALLBB) else: gau.log_print("[*] cALLBB is not initialized. something is wrong!!\n") system.exit() if config.PTMODE: pt = simplept.simplept() else: pt = None gau.log_print("[*] Running vuzzer for '%s'" % (os.path.basename(config.SUT.replace(" ","").replace("%s","")))) if config.ERRORBBON == True: gbb, bbb = dry_run() else: gbb = 0 # gau.die("dry run over..") import timing # selftest() noprogress = 0 currentfit = 0 lastfit = 0 config.CRASHIN.clear() stat = open("stats.log", 'w') stat.write("**** Fuzzing started at: %s ****\n" % (datetime.now().isoformat('+'),)) stat.write("**** Initial BB for seed inputs: %d ****\n" % (gbb,)) stat.flush() os.fsync(stat.fileno()) stat.write( "Genaration\t MINfit\t MAXfit\t AVGfit MINlen\t Maxlen\t AVGlen\t #BB\t AppCov\t AllCov\n") stat.flush() os.fsync(stat.fileno()) starttime = time.clock() allnodes = set() alledges = set() try: shutil.rmtree(config.INPUTD) except OSError: pass shutil.copytree(config.INITIALD, config.INPUTD) # fisrt we get taint of the intial inputs get_taint(config.INITIALD, 1) # print "MOst common offsets and values:", config.MOSTCOMMON # print "Base address: %s"%config.LIBOFFSETS[0] # raw_input("Press enter to continue..") config.MOSTCOMFLAG = True crashhappend = False filest = os.listdir(config.INPUTD) filenum = len(filest) if filenum < config.POPSIZE: gau.create_files(config.POPSIZE - filenum) gau.log_print( '[*] Population at start is about %d files' % (len(os.listdir(config.INPUTD)))) efd = open(config.ERRORS, "w") gau.prepareBBOffsets() writecache = True genran = 0 bbslide = 40 # this is used to call run_error_BB() functions keepslide = 3 keepfilenum = config.BESTP config.SEENBB.clear() # initialize set of BB seen so far, which is 0 del config.SPECIALENTRY[:] todelete = set() # temp set to keep file names that will be deleted in the special folder oldPrintSize = 0 while True: # print "[**] Generation %d\n***********"%(genran,) del config.TEMPTRACE[:] del config.BBSEENVECTOR[:] # this is set when a config.SPECIAL gets at least one new input per generation. SPECIALCHANGED = False config.TMPBBINFO.clear() config.TMPBBINFO.update(config.PREVBBINFO) fitnes = dict() execs = 0 config.cPERGENBB.clear() config.GOTSTUCK = False if config.ERRORBBON == True: if genran > config.GENNUM/5: bbslide = max(bbslide, config.GENNUM/20) keepslide = max(keepslide, config.GENNUM/100) keepfilenum = keepfilenum/2 if 0 < genran < config.GENNUM/5 and genran % keepslide == 0: copy_files(config.INPUTD, config.KEEPD, keepfilenum) # lets find out some of the error handling BBs if genran > 40 and genran % bbslide == 0: stat.write("\n**** Error BB cal started ****\n") stat.flush() os.fsync(stat.fileno()) run_error_bb(pt) copy_files(config.KEEPD, config.INPUTD, len(os.listdir(config.KEEPD))*1/10) # copy_files(config.INITIALD,config.INPUTD,1) files = os.listdir(config.INPUTD) per_gen_fnum = 0 for fl in files: per_gen_fnum += 1 tfl = os.path.join(config.INPUTD, fl) iln = os.path.getsize(tfl) args = (config.SUT % tfl).split(' ') progname = os.path.basename(args[0]) (bbs, retc) = execute(tfl) filecount = len(os.listdir(config.INPUTD)) inputname = os.path.basename(args[1]) per_current_stat = (float(per_gen_fnum)/float(filecount)) * 100 per_show = (int(float(filecount) / 10.0)) if per_show == 0: per_show = 10 if per_gen_fnum % per_show == 0 or per_gen_fnum == filecount: logStr = "[%s] Gen %d : %d%% Executed %d of %d" % (time.strftime("%H:%M:%S"),genran,int(per_current_stat),per_gen_fnum, filecount) if oldPrintSize > 0: dif = oldPrintSize - len(logStr) if dif > 0: logStr += " "*dif oldPrintSize = len(logStr) gau.log_print( logStr ) else: gau.log_print( ' '*oldPrintSize ) sys.stdout.write("\033[F") logStr = "[%s] Gen %d : %d%% Executed %d of %d [%s]" % (time.strftime("%H:%M:%S"),genran,int(per_current_stat),per_gen_fnum, filecount,inputname) if oldPrintSize > 0: dif = oldPrintSize - len(logStr) if dif > 0: logStr += " "*dif oldPrintSize = len(logStr) gau.log_print( logStr ) sys.stdout.write("\033[F") if config.BBWEIGHT == True: fitnes[fl] = gau.fitnesCal2(bbs, fl, iln) else: fitnes[fl] = gau.fitnesNoWeight(bbs, fl, iln) # raw_input() execs += 1 # let us prune the inputs(if at all), whose trace is subset of the new input just got executed. SPECIALADDED = False if config.GOTSPECIAL == True: SPECIALCHANGED = True SPECIALADDED = True todelete.clear() form_bitvector2(bbs, fl, config.BBFORPRUNE, config.SPECIALBITVECTORS) shutil.copy(tfl, config.SPECIAL) config.SPECIALENTRY.append(fl) for sfl, bitv in config.SPECIALBITVECTORS.iteritems(): if sfl == fl: continue if (config.SPECIALBITVECTORS[fl] & bitv) == bitv: tpath = os.path.join(config.SPECIAL, sfl) os.remove(tpath) todelete.add(sfl) config.SPECIALENTRY.remove(sfl) if sfl in config.TAINTMAP: del config.TAINTMAP[sfl] for ele in todelete: del config.SPECIALBITVECTORS[ele] if retc < 0 and retc != -2: efd.write("%s: %d\n" % (tfl, retc)) efd.flush() os.fsync(efd) tmpHash = sha1OfFile(config.CRASHFILE) if tmpHash not in crashHash: crashHash.append(tmpHash) tnow = datetime.now().isoformat().replace(":", "-") nf = "%s-%s.%s" % (progname, tnow, gau.splitFilename(fl)[1]) npath = os.path.join("outd/crashInputs", nf) shutil.copyfile(tfl, npath) if SPECIALADDED == False: shutil.copy(tfl, config.SPECIAL) config.CRASHIN.add(fl) if config.STOPONCRASH == True: # efd.close() crashhappend = True break fitscore = [v for k, v in fitnes.items()] maxfit = max(fitscore) avefit = sum(fitscore)/len(fitscore) mnlen, mxlen, avlen = gau.getFileMinMax(config.INPUTD) gau.log_print( "[*] Done with all input in Gen %d" % (genran) ) gau.log_print( "[*] Calculating code coverage" ) appcov, allcov = gau.calculateCov() tnow = datetime.now().isoformat().replace(":", "-") # stat.write("\t%d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %s\n"%(genran,min(fitscore),maxfit,avefit,mnlen,mxlen,avlen,len(config.cPERGENBB),appcov,allcov,tnow)) stat.write("\t%d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %s\n" % (genran, min( fitscore), maxfit, avefit, mnlen, mxlen, avlen, len(config.SEENBB), appcov, allcov, tnow)) stat.flush() os.fsync(stat.fileno()) gau.log_print( "[*] Wrote to stat.log" ) seenBB = len(config.SEENBB) codeCovStr = "[+] BB Code coverage is %d" % (seenBB) if config.LASTTURNCODECOV != 0: difLastTurnStr = "(no new BB found)" codeCovDif = seenBB - config.LASTTURNCODECOV if codeCovDif > 0: difLastTurnStr = "\033[0;32m(+%d BB)\033[0m" % (codeCovDif) elif codeCovDif < 0: difLastTurnStr = "\033[0;31m(-%d BB)\033[0m" % (codeCovDif) perBBTotal = (float(seenBB) / float(len(config.ALLBB))) * 100 difGoodBB = seenBB - len(config.GOODBB) difGoodBBStr = "no" if difGoodBB > 0: difGoodBBStr = "+%d" % (difGoodBB) elif difGoodBB < 0: difGoodBBStr = "-%d" % (difGoodBB) codeCovStr += " %s (%d%% of all BB) (%s BB dif with good path)" % (difLastTurnStr, perBBTotal, difGoodBBStr) config.LASTTURNCODECOV = seenBB gau.log_print( "-"*len(codeCovStr) ) gau.log_print( codeCovStr ) gau.log_print( "-"*len(codeCovStr) ) if crashhappend == True: break # lets find out some of the error handling BBs # if genran >20 and genran%5==0: # run_error_bb(pt) genran += 1 config.CURRENTGEN += 1 # this part is to get initial fitness that will be used to determine if fuzzer got stuck. lastfit = currentfit # currentfit=maxfit currentfit = len(config.SEENBB) # lastfit-config.FITMARGIN < currentfit < lastfit+config.FITMARGIN: if currentfit == lastfit: noprogress += 1 else: noprogress = 0 if noprogress > 20: config.GOTSTUCK = True stat.write("Heavy mutate happens now..\n") noprogress = 0 if (genran >= config.GENNUM) and (config.STOPOVERGENNUM == True): break if len(os.listdir(config.SPECIAL)) > 0 and SPECIALCHANGED == True: if len(os.listdir(config.SPECIAL)) < config.NEWTAINTFILES: get_taint(config.SPECIAL) else: try: os.mkdir(config.TAINTTMP) except OSError: gau.emptyDir(config.TAINTTMP) if conditional_copy_files(config.SPECIAL, config.TAINTTMP, config.NEWTAINTFILES) == 0: get_taint(config.TAINTTMP) # print "MOst common offsets and values:", config.MOSTCOMMON # gg=raw_input("press any key to continue..") gau.log_print( "[*] Going for new generation creation" ) gau.createNextGeneration3(fitnes, genran) # raw_input("press any key...") efd.close() stat.close() libfd_mm.close() libfd.close() endtime = time.clock() gau.log_print( "[**] Totol time %f sec" % (endtime-starttime,) ) gau.log_print( "[**] Fuzzing done. Check %s to see if there were crashes" % ( config.ERRORS,))