初探BooFuzz
字数 1711 2025-08-05 08:17:20
BooFuzz模糊测试框架深入解析与实战应用
1. BooFuzz框架概述
BooFuzz是Sulley模糊测试框架的一个分支和继承者,在修复了许多错误的同时提升了可扩展性。它是一个功能强大的网络协议模糊测试框架,主要用于发现软件中的安全漏洞。
主要特性
- 轻松快速的数据生成方式
- 仪表板支持(故障检测)
- 失败后的目标重置功能
- 完善的测试数据记录
- 在线文档支持
- 支持任意通信媒介
- 内置支持串行模糊测试、以太网、IP层和UDP广播
- 更好的测试数据记录(统一、彻底、清晰)
- 测试结果通过CSV导出
- 可扩展的仪器/故障检测
- 便捷的安装体验
2. 安装与配置
Ubuntu安装
sudo apt-get install python-pip
git clone https://github.com/jtpereyda/boofuzz.git
cd boofuzz
sudo pip install .
Windows安装
git clone https://github.com/jtpereyda/boofuzz.git
pip install .
3. 核心模块分析
Session模块
Session是BooFuzz的核心模块,负责管理整个模糊测试过程:
pre_send():发送数据后开始遍历Pgraph结构,并沿途fuzz每个组件connect():声明连接关系fuzz():发送负载并开始模糊测试
状态图(Pgraph)机制
BooFuzz通过构建有状态的图(Pgraph)将协议分解为单个请求,并fuzz所有可能路径:
- 以"helo"请求开头
- 完成后开始fuzz"mail from"请求(每个测试用例前加上有效的"helo"请求)
- 继续fuzz"rcpt to"请求(每个测试用例前加上有效的"helo"和"mail from"请求)
- 完成"data"请求后,又转回到从"ehlo"开始
回调函数
可以在图中每个节点定义回调函数,原型如下:
def callback(target, fuzz_data_logger, session, node, edge, *args, **kwargs)
参数说明:
target:目标对象fuzz_data_logger:记录测试检查和通过/失败session:指向会话实例的指针node:要发送的节点edge:当前fuzz到node的最后一条路径
静态协议定义
BooFuzz使用层次化的结构定义协议:
- Request:表示完整的消息
- Blocks:消息中的块
- Primitives:构成块/请求的基本元素(字节、字符串、数字、校验和等)
Block和Group机制
- Block:将独立的primitives组建成有序的块
- Group:包含特定的primitives,与Block结合后,每次调用Block时会循环取出Group中的数据组成不同的Block
示例:
s_initialize("HTTP VERBS")
s_group("verbs", values=["GET", "HEAD", "POST", "TRACE", "PUT", "DELETE"])
if s_block_start("body", group="verbs"):
s_delim(" ")
s_delim("/")
s_string("index.html")
s_delim(" ")
s_string("HTTP")
s_delim("/")
s_string("1")
s_delim(".")
s_string("1")
s_block_end()
常用语法
s_initialize('grammar') # 初始化块请求并命名
s_static("HELLO \r\n") # 始终发送此信息
s_static("PROCESS") # 在HELLO \r\n之后立即发送
s_delim("") # 使用s_delim()原语代替分割符
s_string("AAAA") # 这是我们的fuzz字符串
s_static("\r\n") # 告诉服务器"done"
4. 连接与监控
目标定义
target = sessions.target("10.0.0.1", 5168)
target.netmon = pedrpc.client("10.0.0.1", 26001)
target.procmon = pedrpc.client("10.0.0.1", 26002)
target.vmcontrol = pedrpc.client("127.0.0.1", 26003)
target.procmon_options = {
"proc_name": "SpntSvc.exe",
"stop_commands": ['net stop "trend serverprotect"'],
"start_commands": ['net start "trend serverprotect"'],
}
sess.add_target(target)
sess.fuzz()
监控代理
-
netmon子模块:
- 捕捉网络双向流量并保存
- 在发送数据前记录流量,成功后存入磁盘
-
procmon子模块:
- 检测fuzz过程中发生的故障
- 错误信息存储在"crash bin"文件中
- 可在web监控服务中查看详细crash信息
-
vmcontrol子模块:
- 控制虚拟机(启动、关闭、创建快照等)
- 在目标崩溃时恢复主机状态
请求样例
session.connect(s_get("user"))
session.connect(s_get("user"), s_get("pass"))
session.connect(s_get("pass"), s_get("stor"))
session.connect(s_get("pass"), s_get("retr"))
5. 实战案例:Fuzzing Vulnserver
Vulnserver简介
Vulnserver是一个多线程的基于Windows的TCP服务器,监听端口9999,允许用户运行多个容易受到缓冲区溢出攻击的命令。
基础fuzz脚本
from boofuzz import *
def main():
port = 9999
host = '10.211.55.17'
protocol = 'tcp'
session = Session(
target=Target(
connection=SocketConnection(host, port, proto=protocol),
),
)
s_initialize("trun")
s_string("TRUN", fuzzable=False)
s_delim(" ", fuzzable=False)
s_string("FUZZ")
s_static("\r\n")
session.connect(s_get("trun"))
session.fuzz()
if __name__ == "__main__":
main()
增强功能
1. 添加回调函数
session.connect(s_get("trun"), callback=get_banner)
def get_banner(target, my_logger, session, *args, **kwargs):
banner_template = "Welcome to Vulnerable Server! Enter HELP for help."
try:
banner = target.recv(10000)
except:
print("Unable to connect. Target is down. Exiting.")
exit(1)
my_logger.log_check('Receiving banner..')
if banner_template in banner:
my_logger.log_pass('banner received')
else:
my_logger.log_fail('No banner received')
print("No banner received, exiting..")
exit(1)
2. 日志记录
csv_log = open('fuzz_results.csv', 'wb')
my_logger = [FuzzLoggerCsv(file_handle=csv_log)]
fuzz_loggers = my_logger
3. 进程监控
procmon = pedrpc.Client(host, 26002)
procmon_options = {
"proc_name": "vulnserver.exe",
"stop_commands": ['wmic process where (name="vulnserver") delete'],
"start_commands": ['vulnserver.exe'],
}
完整fuzz脚本
from boofuzz import *
from sys import exit
def get_banner(target, my_logger, session, *args, **kwargs):
banner_template = "Welcome to Vulnerable Server! Enter HELP for help."
try:
banner = target.recv(10000)
except:
print("Unable to connect. Target is down. Exiting.")
exit(1)
my_logger.log_check('Receiving banner..')
if banner_template in banner:
my_logger.log_pass('banner received')
else:
my_logger.log_fail('No banner received')
print("No banner received, exiting..")
exit(1)
def main():
port = 9999
host = '127.0.0.1'
protocol = 'tcp'
s_initialize("Vulnserver")
s_group("verbs", values=["TRUN", "GMON", "KSTET"])
if s_block_start("test", group="verbs"):
s_delim(" ")
s_string("AAA")
s_string("\r\n")
s_block_end("test")
csv_log = open('fuzz_results.csv', 'wb')
my_logger = [FuzzLoggerCsv(file_handle=csv_log)]
session = Session(
target=Target(
connection=SocketConnection(host, port, proto=protocol),
procmon=pedrpc.Client(host, 26002),
procmon_options={
"proc_name": "vulnserver.exe",
"stop_commands": ['wmic process where (name="vulnserver") delete'],
"start_commands": ['vulnserver.exe'],
}
),
fuzz_loggers=my_logger,
crash_threshold_element=1, # Crash多少次后停止
)
session.connect(s_get("Vulnserver"), callback=get_banner)
session.fuzz()
if __name__ == "__main__":
main()
6. 监控与分析
Web界面
访问http://127.0.0.1:26000可以观察fuzz测试进度,显示完整性和导致崩溃的输入文件。
结果分析
- 查看
fuzz_results.csv文件获取payload信息 - 分析崩溃时的寄存器状态(如EIP被41414141覆盖)
- 使用记录的payload进行复现和利用
7. 最佳实践
- 协议建模:准确建模目标协议的状态转换
- 监控配置:合理配置netmon、procmon和vmcontrol
- 回调函数:使用回调函数增强测试逻辑
- 日志记录:充分利用CSV日志和Web界面
- 崩溃阈值:设置合理的crash_threshold_element
- 测试范围:使用s_group覆盖所有可能的命令和参数