Boofuzz源码解析
boofuzz源码分析
以ftp_simple.py
为例:
1 |
|
其中,define_proto()
将调用session.connect()
构造调用流图。如果connect(node1)
的参数只有只有一个,那么该节点将保存在self.nodes
变量中,同时会创建self.root
到该节点的边;如果connect(node1, node2)
,node1和node2节点信息都将保存在self.nodes
变量中,同时会创建node1到node2的边
1 |
|
session.fuzz()
核心代码在_main_fuzz_loop
中
在_main_fuzz_loop
中:
self.server_init()
:启动web_interface_thread
(网络接口线程:默认为localhost:26000)
self._start_target()
:启动一个boofuzz.sessions.Target实例
相关变量
变量名 | 含义 |
---|---|
self.num_cases_actually_fuzzed | 实际fuzz的测试用例数 |
mutation_context | 变异上下文 |
fuzz_case_iterator | fuzz测试用例迭代器 |
遍历fuzz_case_iterator
中的mutation_context
,
如果设置了
restart_interval
,表明每次运行restart_interval
个测试用例后重启target_fuzz_current_case()
函数对当前的测试用例进行模糊测试,而该测试用例由fuzz_case_iterator
控制:_pause_if_pause_flag_is_set()
函数pause flag
是否被唤起,如果被唤起,则进入一个无限循环中等待其变为False(Why?)self._test_case_name()
函数用于构造测试用例名,测试用例名字格式为:message_path:[qualified_name1:mutation.index1, qualified_name2:mutation.index2, ...]
,例如user:[user.key:0]
self._fuzz_data_logger.open_test_case()
记录测试用例,默认是讲保存插入测试用例信息的sql语句添加到self._queue
队列中。(在何处执行?在此处执行)self._open_connection_keep_trying()
尝试与服务器进行连接(建立套接字并连接),如果是因为可用套接字数不够导致的错误,那就再进行50轮*5s的判断【如果在这段时间内有可以创建套接字,则继续进行,否则将报错】。self._pre_send(target)
:不知道干啥的self.transmit_fuzz()
:self.fuzz_node.render()
:渲染模糊测试节点数据- 渲染完成后,由self.targets[0]来发送该数据
- 如果
self._receive_data_after_fuzz
为True
,则将返回的信息保存到received变量中
self._check_for_passively_detected_failures()
:被动检查错误。首先,需要遍历target.monitors
该数组两遍,第一遍检查所有的monitor,判断其是否报告一个错误,如果报告了错误,那么需要收集一个崩溃信息【不确定是否monitor一定会提供一个崩溃信息,但以防万一还是要检查一下】;在第二遍,我们尝试从未检测到崩溃的监视器中获取崩溃概要作为补充信息。如果未检测到错误,则输出”No crash detected.”,并返回是否崩溃的标志如果
self._reuse_target_connection
(重用目标连接)为假,那么直接关闭连接最后进行三个操作:
self._process_failures()
【处理错误】、self._fuzz_data_logger.close_test_case()
【将日志写到数据库中】和self.export_file()
【将对象值导出到本地磁盘/需要设置self.session_filename
】
详解fuzz_case_iterator
:
- 最先传入的是
self._generate_mutations_indefinitely(max_depth=max_depth)
【默认 max_depth 为 None 】
1 |
|
- 接着就是分析内层生成器,i.e.
self._generate_n_mutations(depth=depth, path=path)
:
1 |
|
1⃣ self._iterate_protocol_message_paths(path=path)
:
1 |
|
该函数self._iterate_protocol_message_paths_recursive
的作用是返回一个以边构成的路径(请求序列)
1 |
|
以boofuzz的提供的ftp脚本ftp_simple.py
为例,其请求依赖流图如下所示:
graph TB
a((root))-->b((user))-->c((pass))-->d((stor))
c-->e((retr))
_iterate_protocol_message_paths_recursive
生成器将会生成path有:[user]
, [user, pass]
, [user, pass, stor]
, [user, pass, retr]
2⃣ self._generate_n_mutations_for_path(path, depth=depth)
:
1 |
|
该函数self._generate_n_mutations_for_path_recursive
的作用是
1 |
|
self._generate_mutations_for_request
–> self.fuzz_node.get_mutations
–> self.mutations
–> item.get_mutations()
–>mutations() [in string.py]
,
这里需要注意的是,boofuzz/primitives/string.py
中定义了一些字典值,存放在变量self._fuzz_library
中
1 |
|
该调用链每次会构造一个变异类,然后在_main_fuzz_loop
模糊测试大循环中使用:
1 |
|
总结
简单来说,boofuzz总体流程是:1. 遍历请求序列流图(树)并构造序列;2. 产生变异数据;3. 发送到目标服务器
boofuzz整体框架如下图所示: