hackedteam/fuzzer-windows

View on GitHub
fontfuzzer/fuzzers/browser.py

Summary

Maintainability
A
25 mins
Test Coverage
#!/usr/bin/env python

import sys
sys.path.append('../')
import parsers.TTF as TTF

import re
import os

import random
import string
import uimodules

import tornado.web
import tornado.ioloop
import tornado.httpserver


FUZZING_INSTANCES = {}

class MainHandler(tornado.web.RequestHandler):
    
    def get(self):

        # force 'IE9 standards' document mode, otherwise it will switch to quirks mode and fonts won't be rendered
        self.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">') 
        self.write('<html><body>')

        self.write('Active instances: {}<br>'.format(len(FUZZING_INSTANCES.keys())))
        for i in FUZZING_INSTANCES:
            self.write('{} <a href="/font/{}">Go</a><br>'.format(i, i))



        # list available folder with samples in a radio button
        self.write('<form action="/" method="post">')

        folders = []
        for d in [ os.path.join( os.path.dirname(__file__), 'static', d) for d in os.listdir(  os.path.join( os.path.dirname(__file__), 'static') ) ]:
            if os.path.isdir(d) and re.match( '[0-9]{10}', os.path.basename(d)) == None: # skip also generated testcases
                folders.append(d)


        for d in folders:
            self.write('<input type="radio" name="folder" value="{}">{}<br>'.format(os.path.basename(d), os.path.basename(d)))
        
        

        self.write('<input type="submit" value="Start fuzzing">'
                   '<input type="hidden" name="newInstance" value="newInstance">'
                   '</form>')


        self.write('</html></body>')


    def post(self):
        
        self.set_header('Content-Type', 'text/plain')

        try:
            self.get_argument("newInstance")
            folder = self.get_argument('folder')
        except tornado.web.MissingArgumentError:
            self.write('Wrong post')
            return


        while True:
            instanceId = ''.join([random.choice(string.digits) for i in range(0, 10) ])
            if instanceId not in FUZZING_INSTANCES.keys():
                break
            
        
        self.redirect('/font/{}/{}'.format(instanceId, folder))



class FontFuzzer(tornado.web.RequestHandler):

    def initialize(self):
                
        # generate samples for this run
        self.fontsPath = []


    
    def get(self, instanceId, folder):


        # don't remember wheter initialize is called upon every call..
        self.fontsPath = []

        testcasesFolder = 'static/{}'.format(instanceId)
        
        if instanceId not in FUZZING_INSTANCES.keys():
            os.mkdir(testcasesFolder)
            FUZZING_INSTANCES[instanceId] = ''


        # 1] folder must exists
        fontSourceFolder = os.path.join(os.path.dirname(__file__), 'static/{}'.format(folder))
        if not os.path.isdir(fontSourceFolder):
            self.write('Folder {} doesn not exist - can\'t create testcases'.format(folder))
            return
        

        # 2] generate samples
        fonts = {}
        for font in os.listdir(fontSourceFolder):
            try:
                abspath = os.path.abspath( os.path.join(fontSourceFolder, font) )
                tt = TTF.TTFont(abspath)
                fonts[abspath] = tt
            
                print '[*] Fuzzing {}'.format(abspath)
            
                #fonts[abspath].fuzzFontBytecode()
                #fonts[abspath].fuzzDirectoriesBitFlipping()
                #fileInMemory = fonts[abspath].fuzzCffTableBitFlipping()
                fileInMemory = fonts[abspath].fuzzFontBytecode()
            
                testcaseName = os.path.abspath( os.path.join( testcasesFolder,
                                                              os.path.basename(abspath).split('.otf')[0] + '_' +
                                                              ''.join( random.choice( string.ascii_lowercase + string.digits) for x in range(8) ) + '.otf')
                                                )

                open( testcaseName, 'wb').write(fileInMemory)
                self.fontsPath.append( '/static' + testcaseName.split('/static')[1] )
                                       

            except Exception as e:
                print e
                



        self.render('testcase.html', fonts=self.fontsPath, instanceId=instanceId, folder=folder) 




if __name__ == '__main__':

    settings = { "ui_modules": uimodules,
                 "static_path": os.path.join( os.path.dirname(__file__), "static"),
                 }    

    
    # map ULRs/patterns to RequestHandlers
    application = tornado.web.Application( 
        handlers = [ (r'/', MainHandler), 
                     (r'/font/([0-9]{10})/(.+)', FontFuzzer), 
                     ],
        **settings)
    
    server = tornado.httpserver.HTTPServer(application)
    server.listen(80)
    tornado.ioloop.IOLoop.instance().start()