BFuzz 源码分析

2023-02-12 本文阅读量

学习fuzz,狂看代码。

BFuzzgithub上的开源的一款浏览器fuzz工具,现有的代码感觉也不能算得上fuzz工具,最多说得上是用浏览器跑html页面测试用例的工具。

基本原理

用法是:

warmachine@ftw:~/BFuzz$ ./generate.sh
warmachine@ftw:~/BFuzz$ python BFuzz.py 
Enter the browser type:
 1: Chrome 
 2: Firefox
>>

该工具的原理是先用domato生成测试用例,保存在recurve目录中。然后根据选择fuzz的浏览器类型,遍历recurve目录下的html文件,并调用浏览器进行加载,来看是否会造成浏览器崩溃,以此来实现fuzz

源码分析

样例生成

首先看generate.sh调用domato来生成测试用例,该sh内容如下:

#!/bin/bash
cd domato
python generator.py --output_dir ../recurve/ --no_of_files 50

可以看到进到集成的domato目录下,调用generator.py生成50个测试用例,保存在recurve目录下。

对于测试用例的生成与变异,该框架并没有做什么操作,而是直接用的现成的domatodomato是基于规则生成的样例生成工具,该框架相对还比较复杂,对于该框架的分析不属于BFuzz的分析范畴,可以去读一读domato源码。

样例运行

生成了样例之后,就是用浏览器运行生成的样例并查看生成的结果,来看BFuzz是如何做的。

BFuzz.py是实现该功能的代码,代码行数只有60行,功能是简单的目录遍历并调用浏览器执行样本。

下面对源码进行分析,入口是runWebTest函数:

// BFuzz.py: 59
if __name__ == '__main__':
    runWebTest()
 
// BFuzz.py: 9
def runWebTest():
    dir_path = os.path.dirname(os.path.realpath(__file__))
    print("Enter the browser type:  \n 1: Chrome \n 2: Firefox")
    browserType = input('>>')
    timeout = input(
        "Duration the browser process should wait before stopping(>=15 seconds to ensure full load of page):")
    checkValidBrowserType(browserType)
    for root, folders, fileNames in os.walk("recurve"):
        for fileName in fileNames:
            if not fileName.endswith('.html'):
                continue
            processCommand = getBrowserApplication(browserType)
            if processCommand is not None:
                setupExploit(dir_path, fileName, processCommand, root)
                runExploit(processCommand, timeout)
            else:
                print "Invalid Browser Type"

runWebTest函数先获取项目的文件夹路径dir_path,然后让输入要fuzz的类型是chrome还是firefox(项目只支持对这二者的fuzz),然后再输入一个timeout,该变量让用户决定每次启动浏览器运行一个样例要等多久。

输入完成后,调用checkValidBrowserType检查选择的浏览器类型是否正确。

// BFuzz.py: 53
def checkValidBrowserType(browserType):
    if browserType not in [1, 2]:
        print("Incorrect option!!")
        sys.exit(0)

在检查完类型以后,for root, folders, fileNames in os.walk("recurve")遍历recurve文件夹,如果文件后缀不是html,则跳过。

根据选择的浏览器类型,调用getBrowserApplication函数获取稍后启动浏览器所需的路径以及参数。可以看到对于chrome浏览器,启动的命令是google-chrome;对于firefox,启动的命令是firefox -new-tab

// BFuzz.py: 43
def getBrowserApplication(browserType):
    if browserType == 1:
        processCommand = ['google-chrome']
    elif browserType == 2:
        processCommand = ['firefox', '-new-tab']
    else:
        processCommand = None
    return processCommand

获取了程序的启动命令后,调用setupExploit函数来构造最终的启动命令。将html文件路径作为参数拼接到启动命令的后面,形成完整的启动命令。如样例的绝对路径是/tmp/recurve/a.html的话,最终chrome运行的参数是google-chrome file://tmp/recurve/a.htmlfirefox -new-tab file://tmp/recurve/a.html

// BFuzz.py: 36
def setupExploit(dir_path, fileName, processCommand, root):
    filePath = os.path.join(dir_path, root, fileName)
    filePath = "file://" + filePath
    print "Testing with exploit:" + filePath
    processCommand.append(filePath)

最终调用runExploit函数来启动浏览器运行样例,调用subpocess.Popen直接启动浏览器运行样例。

// BFuzz.py: 28
def runExploit(processCommand, timeout):
    print "Executing Command: " + " ".join(processCommand)
    process = subprocess.Popen(processCommand)
    sleep(timeout)
    # print "Killing browser process.... bye bye"
    sleep(3)

总结

总的来说这个项目不是一个完整的fuzzer,它没有崩溃监控,也没有样本保存,从它的ToDo中也可以看到它想做的事,但是项目已经很久没更新了,计划成了永远的计划。

ToDo
Handle Exeception, Add banner, Optimize Code, Mangle testcases.

但是从这个项目中也可以看到一个基本的fuzzer的影子,看到了样本的生成以及运行,可以作为fuzzer学习的demo。不过domato才是样例生成的关键,它里面的代码不是那么简单。

参考

  1. BFuzz
  2. domato