Boofuzz协议漏洞挖掘入门教程与使用心得
Posted ronnie88597
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Boofuzz协议漏洞挖掘入门教程与使用心得相关的知识,希望对你有一定的参考价值。
文章目录
本文主要涉及到对Boofuzz的简单介绍,以及基于Boofuzz官方文档/网上资料的学习、整理和翻译相关内容,希望对想要入门的Boofuzz的朋友有所帮助,谢谢~
1.简介
模糊技术主要的两种形式:
- 基于变异的模糊化,mutation-based fuzzing,该技术主要包括以下:
- 收集已知的良好数据,如文件或网络流量;
- 通过随机/启发式等方式方法,对数据进行稍微地修改;
- 基于生成的模糊化,generation-based fuzzing,从描述特定格式或网络协议报文格式规范或RFC开始,生成具有一定差异的有效测试用例数据,以便在测试的应用程序中造成崩溃。
模糊测试中,应该避免过度转换数据,否则应用程序可能会很快将输入作为无效输入拒绝。
接下来我们提到的Sulley和Boofuzz都是属于基于生成的模糊化fuzzer。
1.1.从Sulley说起
Sulley不仅具有令人印象深刻的数据生成能力,而且还朝着更进一步的方向迈进了一步,其中还包括现代模糊器应提供的许多其他重要方面。Sulley监视网络并有条不紊地维护记录。Sulley可以检测和监视目标的运行状况,并可以使用多种方法将其恢复到已知的良好状态。Sulley对检测到的故障进行检测,跟踪和分类。Sulley可以并行进行测试,从而显着提高测试速度。Sulley可以自动确定哪些独特的测试用例序列会触发故障。Sulley可以自动完成所有这些工作。
上图是Sulley的整体框架图,来源于BlackHat。Sulley主要包括四大组件
- Data Generation,数据生成
- Session,会话管理
- Agents,代理
- Utilities,独立单元工具
其中,数据生成和会话管理是比较重要的两个模块。Sulley数据生成方式是基于generation-based的方式,需要对协议或者文件进行建模。数据生成的特点:
- 一个数据报文由基元(Primitives)、块(Blocks组成);
- 多个基元可以组成块,块可以相互嵌套;
- 在基元的基础上我们可以创建自定义的特殊的复杂基元(Legos,数据积木,暂且这么翻译吧),例如Email的地址,IP地址等;
- 最后还有一些有用的工具,例如算length长度、校验和、加密模块等;
1.2.Boofuzz
Boofuzz是一个基于生成(generation-based)的协议Fuzz工具,它通过python语言来描述协议的格式。
Boofuzz是著名的Sulley fuzzing框架的一个分支和继承者。除了众多的bug修复之外,boofuzz还致力于扩展性。
2.Dev环境部署
2.1.使用pip安装部署
强烈建议在虚拟环境(venv)中设置boofuzz。首先,创建一个目录来保存boofuzz安装:
$ mkdir boofuzz && cd boofuzz
$ python3 -m venv env
这将在当前文件夹中创建一个新的虚拟环境env。请注意,虚拟环境中的Python版本是固定的,并在创建时选择。与全局安装不同,在虚拟环境中,python被别名为虚拟环境的python版本。
接下来,激活虚拟环境:
source env/bin/activate
如果在windows平台上,使用命令:
env\\Scripts\\activate.bat
使用一下命令更pip
和setuptools
:
(env) $ pip install -U pip setuptools
最后安装boofuzz
(env) $ pip install boofuzz
要运行和测试模糊脚本,请确保始终事先激活虚拟环境。
2.2.从源码部署boofuzz
#!/bin/bash
sudo echo
if [ ! -d ~/work_dir/boofuzz-F ];then
mv ~/Downloads/boofuzz-F ~/work_dir
fi
sudo apt-get install -y python3-pip \\
python3-venv \\
build-essential
pip install -U pip setuptools
pip install pcapy impacket wheel
cd ~/work_dir/boofuzz-F
python3 -m venv env
source env/bin/activate
pip install -e .[dev]
使用HTTP代理时,需要设置环境变量:
set HTTPS_PROXY=http://your.proxy.com:port
2.3.进程监控
process monitor是在Windows或Linux上检测崩溃和重新启动应用程序的工具。虽然boofuzz通常在与目标不同的机器上运行,但进程监视器必须在目标机器本身上运行。
注意:windows平台使用
process_monitor.py
,*nix平台使用process_monitor_unix.py
;
2.4.网络监控,network_monitor.py
网络监视器是Sulley记录测试数据的主要工具,已经被boofuzz的记录机制所取代。然而,有些人仍然更喜欢PCAP方法。
注意:
网络监视器需要Pcapy和Impacket,它们不会随着boofuzz自动安装。
您可以使用
pip install pcapy impacket
手动安装它们。如果遇到错误,请查看Pcapy项目(https://github.com/helpsystems/pcapy)页面上的要求。
3.入门快速使用
一般fuzz的流程为:
- 实例化
Session
对象 - 定义消息(Request)
- 构建协议树(Protocol-Tree)
- Fuzz
- 查看结果
3.1.实例化Session
对象
Session
对象是fuzz会话的中心。创建时,将向其传递一个Target
对象,该对象本身将接收一个Connection
对象。例如:
session = Session(
target=Target(
connection=TCPSocketConnection("127.0.0.1", 8021)))
Connection
对象实现ITargetConnection
接口。可用的子类包括:
TCPSocketConnection
UDPSocketConnection
SSLSocketConnection
RawL2SocketConnection
RawL3SocketConnection
SocketConnection (depreciated)
SerialConnection
3.2.定义消息(Request)
会话对象就绪后,接下来需要在协议中定义消息。
每个消息都是一个请求对象,其子对象定义该消息的结构。
以下是FTP协议中的几个消息定义:
user = Request("user", children=(
String("key", "USER"),
Delim("space", " "),
String("val", "anonymous"),
Static("end", "\\r\\n"),
))
passw = Request("pass", children=(
String("key", "PASS"),
Delim("space", " "),
String("val", "james"),
Static("end", "\\r\\n"),
))
stor = Request("stor", children=(
String("key", "STOR"),
Delim("space", " "),
String("val", "AAAA"),
Static("end", "\\r\\n"),
))
retr = Request("retr", children=(
String("key", "RETR"),
Delim("space", " "),
String("val", "AAAA"),
Static("end", "\\r\\n"),
))
3.3.构建协议树(Protocol-Tree)
定义消息后,您将使用刚才创建的会话对象将消息(Request)连接到图形(graph)中,构建协议树(Protocol-Tree):
session.connect(user)
session.connect(user, passw)
session.connect(passw, stor)
session.connect(passw, retr)
当模糊化时,boofuzz将在模糊化passw之前发送user,在模糊化stor或retr之前发送user和passw。
从以上的表述可以看出,构建协议树(Protocol-Tree),其实是
Session
对象组织维护了以root
为根节点的消息(Request)状态转移图(graph)。若要绘制Session构建的消息(Request)状态转移图(graph),使用以下代码
with open('somefile.png', 'wb') as file: file.write(session.render_graph_graphviz().create_png())
需要注意,绘图前请确保系统中已经安装好了
graphviz
,如果没有,使用命令sudo apt install graphviz -y
进行安装。将上述例子中的协议树(Protocol-Tree)画出来,如下所示:
3.4.Fuzz
最后即可开始模糊测试
session.fuzz()
请注意,此时您只有一个非常基本的模糊器。
项目中的examples
目录中有一些示例和请求定义可能有助于您进一步了解。
3.5.查看结果
每次运行的日志数据将保存到当前工作目录中boofuzz results目录中的SQLite数据库中。您可以随时使用重新打开这些数据库上的web界面
$ boo open <run-*.db>
检查响应,您需要使用Session.post_test_case_callbacks
回调函数。要在请求中使用响应中的数据,请参阅ProtocolSessionReference
。
4.必备知识汇总
我在这里罗列了几个值得重点关注的点:
- s_*系列函数;
- 很多s_*系列函数都有一个bool类型的参数
fuzzable
,它是控制是否对某个字段进行fuzz的开关; - Session.connect函数;
- Session.fuzz函数;
4.1.会话,Session
Session继承扩展了pgraph.graph类,pgraph是操纵有向图和无向图的python库,Session在graph类基础上提供用于架构协议会话的容器。
常用函数包括:
-
connect,构建协议树时,用来连接消息节点;
-
add_target,添加目标;
-
example_test_case_callback;
-
register_post_test_case_callback,注册一个测试后用例方法。注册的方法将在每个模糊测试用例之后调用。调用的顺序:
pre_send() ↓ req ↓ callback ↓ ... ↓ req ↓ callback ↓ post-test-case-callback
-
fuzz,模糊整个协议树(Protocol-Tree)。迭代并模糊所有情况,根据
self.skip
跳过并根据self.restart_interval
重新启动。如果希望模糊测试结束后,web服务器仍然可用,则程序必须在结尾调用boofuzz.helpers.pause_for_signal()
; -
import_file
-
num_mutations,图中的总突变数。此函数会更新成员变量
self.total_num_mutations
; -
transmit_fuzz
-
transmit_normal
-
render_graph_graphviz,渲染图。使用代码:
with open('somefile.png', 'wb') as file: file.write(session.render_graph_graphviz().create_png())
4.2.目标,Target
目标描述符容器。
常用函数包括:
- set_fuzz_data_logger,设置此对象的模糊数据记录器——用于发送和接收的模糊数据;
4.2.1.Repeater
基础的重复器类
4.2.2.TimeRepeater
基于时间的重复器类。启动计时器,并重复,直到超过持续时间秒。
4.2.3.CountRepeater
基于数量的重复器。重复固定的次数。
4.3.连接,Connection
连接对象,网络层连接描述类。
4.3.1.ITargetConnection
用于连接模糊目标的接口。
4.3.2.BaseSocketConnection
该类是套接字(socket)上许多连接的基础类。
4.3.3.TCPSocketConnection
用于TCP套接字的BaseSocketConnection实现。
4.3.4.UDPSocketConnection
用于UDP套接字的BaseSocketConnection实现。
4.3.5.SSLSocketConnection
用于SSL套接字的BaseSocketConnection实现。
4.3.6.RawL2SocketConnection
用于网络L2层的BaseSocketConnection实现。
4.3.7.RawL3SocketConnection
用于网络L3层的BaseSocketConnection实现。
4.3.8.SocketConnection
ITargetConnection使用套接字实现。
4.3.9.SerialConnection
ITargetConnection实现通用串行端口。
4.4.监视器,Monitors
监控器是针对特定行为监控目标的组件。监视器可以是被动的,只是观察和提供数据,或者更主动地与目标直接交互。某些监控器还具有启动、停止和重新启动目标的功能。
根据您在目标主机上可用的工具,检测目标的崩溃或不当行为可能是一个复杂、非直接的过程;这尤其适用于嵌入式设备。Boofuzz提供了三种主要的监视器实现:
-
ProcessMonitor,在Windows和Unix上从进程收集调试信息的监视器。它还可以重新启动目标进程并检测故障。
-
NetworkMonitor,一种通过PCAP被动捕获网络流量并将其附加到测试用例日志的监视器。
-
CallbackMonitor,用于实现可提供给会话类的回调。
4.4.1BaseMonitor
目标监视器的接口。所有监视器必须遵守本规范。
4.4.2.ProcessMonitor
进程监视器由两部分组成:
- ProcessMonitor类,实现BaseMonitor;
- 要在目标主机上运行的模块,windows平台使用
process_monitor.py
,*nix平台使用process_monitor_unix.py
;
4.4.3.NetworkMonitor
网络监视器由两部分组成:
-
NetworkMonitor类,它实现BaseMonitor;
-
要在目标主机上运行的模块,使用
network_monitor.py
4.4.4.CallbackMonitor
Session中用于提供回调数组的新型回调监视器。它的目的是在会话类中保留*_callbacks
参数,同时通过将这些回调转发到监视器基础结构来简化会话的实现。
参数到此类的方法实现的映射关系,如下所示:
- restart_callbacks –> target_restart
- pre_send_callbacks –> pre_send
- post_test_case_callbacks –> post_send
- post_start_target_callbacks –> post_start_target
所有其他实现的接口成员都只是存根(stubs),因为会话中不存在相应的参数。在任何情况下,实现自定义监视器可能比使用回调函数更明智。
4.5.日志,Logging
Boofuzz提供了灵活的日志记录。所有日志类都实现IFuzzLogger。下面详细介绍了内置日志类。
要同时使用多个记录器,请参阅 FuzzLogger
。
4.5.1.IFuzzLogger
用于记录模糊数据的抽象类。
IFuzzLogger为Sulley框架和测试编写器提供了日志接口。
提供的方法旨在反映功能测试动作。IFuzzLogger提供了一种记录测试用例、通过、失败、测试步骤等的方法,而不是一般的调试/信息/警告方法。
这个假设的示例输出给出了如何使用记录器的想法:
-
Test Case: UDP.Header.Address 3300
Test Step: Fuzzing
Send: 45 00 13 ab 00 01 40 00 40 11 c9 …
Test Step: Process monitor
checkCheck OK
Test Step: DNP
CheckSend: ff ff ff ff ff ff 00 0c 29 d1 10 …
Recv: 00 0c 29 d1 10 81 00 30 a7 05 6e …
Check: Reply is as expected. Check OK
-
Test Case: UDP.Header.Address 3301
Test Step: Fuzzing
Send: 45 00 13 ab 00 01 40 00 40 11 c9 …
Test Step: Process monitor check
Check Failed: “Process returned exit code 1”
Test Step: DNP Check
Send: ff ff ff ff ff ff 00 0c 29 d1 10 …
Recv: None
Check: Reply is as expected. Check Failed
为每个模糊案例打开一个测试案例。为每个高级测试步骤打开一个测试步骤。测试步骤可以包括,例如:
- Fuzzing
- Set up (pre-fuzzing)
- Post-test cleanup
- Instrumentation checks
- Reset due to failure
在测试步骤中,测试可以记录发送的数据、接收的数据、检查、检查结果和其他信息。
4.5.2.IFuzzLoggerBackend
IFuzzLogger的别名
4.5.3.FuzzLoggerText
此类格式化FuzzLogger数据以用于文本显示。可以将其配置为输出到标准输出或命名文件。
使用两个FuzzLoggerText,可以将FuzzLogger实例配置为输出到控制台和文件。
4.5.4.FuzzLoggerCsv
此类为pcap文件格式化FuzzLogger数据。可以将其配置为输出到命名文件。
4.5.5.FuzzLoggerCurses
此类使用curses为控制台GUI格式化FuzzLogger数据。这还没有在Windows上测试过。
4.5.6.FuzzLogger
获取IFuzzLogger对象的列表,并将记录的数据多路传输到每个对象。
FuzzLogger还维护概要故障和错误数据。
4.6.协议定义,Protocol Definition
有关老式Spike样式的静态协议定义格式,请参阅静态协议定义函数。这里描述的非静态协议定义是较新的(但仍有些实验性)方法。
请求是消息,消息中包含了块,原语(Primitives)是块/请求的组成(bytes, strings, numbers, checksums等)。
下面是一个HTTP消息的示例。它演示了如何使用请求、块和几个原语:
req = Request("HTTP-Request",children=(
Block("Request-Line", children=(
Group("Method", values= ["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE"]),
Delim("space-1", " "),
String("URI", "/index.html"),
Delim("space-2", " "),
String("HTTP-Version", "HTTP/1.1"),
Static("CRLF", "\\r\\n"),
)),
Block("Host-Line", children=(
String("Host-Key", "Host:"),
Delim("space", " "),
String("Host-Value", "example.com"),
Static("CRLF", "\\r\\n"),
)),
Static("CRLF", "\\r\\n"),
))
4.6.1.Request
顶层容器。可以保存任何块结构或原语(Primitives)。
这基本上可以被认为是超级块、根块、父块等别名。
4.6.2.Blocks
基本构建块。可以包含primitives, sizers, checksums或其他blocks。
4.6.3.Primitives
-
Static
静态原语是固定的,在模糊化时不会发生变化。
-
Simple
只能通过简单手动指定的,模糊字节值。
-
Delim
分隔符,它的突变包括重复、替换和排除。分隔符包括:,\\r,\\n, ,=,>,<等等;
-
Group
此原语表示,在突变时将便利一个指定的静态值列表的每个元素。
可以将块绑定到组原语,以指定块应循环遍历组中每个值的所有可能突变。例如,group原语在表示有效操作码列表时非常有用。
下面是Group原语表示HTTP请求方法的所有突变的可能。
with s_block("Request-Line"): s_group("Method", ["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE"]) s_delim(" ", name="space-1") s_string("/index.html", name="Request-URI") s_delim(" ", name="space-2") s_string("HTTP/1.1", name="HTTP-Version") s_static("\\r\\n", name="Request-Line-CRLF") s_string("Host:", name="Host-Line") s_delim(" ", name="space-3") s_string("example.com", name="Host-Line-Value") s_static("\\r\\n", name="Host-Line-CRLF") s_static("\\r\\n", "Request-CRLF")
-
RandomData
生成随机数据块,同时保留原始数据的副本。
可以指定随机长度范围。对于静态长度,请将最小/最大长度设置为相同。 -
String
在“坏”字符串库中循环的基元。
类变量“fuzz_library”包含所有实例的全局智能模糊值列表。当前我使用的代码中的_fuzz_library如下:_fuzz_library = [ "!@#$%%^#$%#$@#$%$$@#$%^^**(()", "", # strings ripped from spike (and some others I added) "$(reboot)", "$;reboot", "%00", "%00/", ......... '%0DCMD=$"reboot";$CMD', "%0Dreboot", "%n" * 500, "%s" * 100, "%s" * 500, "%u0000", "& reboot &", "& reboot", "&&CMD=$'reboot';$CMD", '&&CMD=$"reboot";$CMD', "&&reboot", "&&reboot&&", "..:..:..:..:..:..:..:..:..:..:..:..:..:", "/%00/", "/." * 5000, "/.../" + "B" * 5000 + "\\x00\\x00", "/.../.../.../.../.../.../.../.../.../.../", "/../../../../../../../../../../../../boot.ini", "/../../../../../../../../../../../../etc/passwd", "/.:/" + "A" * 5000 + "\\x00\\x00", "/\\\\" * 5000, "/index.html|reboot|", "; reboot", ";CMD=$'reboot';$CMD", ';CMD=$"reboot";$CMD', ";id", ......... ]
_fuzz_library库变量包含特定于实例化原语的模糊值。这允许我们避免在每个实例化的原语中复制大约70MB的_fuzz_library数据结构。
-
FromFile
循环浏览文件中的“坏”值列表。
获取文件名并打开文件以读取模糊化过程中使用的值。文件名可能包含通配符(glob characters)。 -
Mirror
原语用于使用另一个原语保持更新。
-
BitField
位字段原语表示许多可变长度,用于定义所有其他整数类型。
-
Byte
1个字节大小的位字段原语。
-
Bytes
将任意长度的二进制字节字符串模糊化的原语。
-
Word
2个字节大小的位字段原语。
-
DWord
4个字节大小的位字段原语。
-
QWord
8个字节大小的位字段原语。
4.6.4.制作自己的块/原语
要创建自己的块/基本体,请执行以下操作:
- 从
Fuzzable
或FuzzableBlock
继承一个自定义块/原语类; - override父类的
mutations
和/或encode
的方法;
Overload,Override,Overwrite区别
- Overload重载,同一个作用域中,语义功能相似,仅函数名相同;
- Override覆盖,继承关系中,Override一般用于多态技术,函数必须实现基类的统一接口;
- Overwrite重写,继承关系中,子类函数名与父类相同。
- 可选:创建附带的静态原语函数。示例,请参见boofuzz的
__init__.py
文件。
如果您的块依赖于对其他块的引用,那么校验和或长度字段依赖于消息的其他部分的方式,请参阅Size
源代码以获取如何避免递归问题,并小心。
Fuzzable
自定义块/原语时,需要继承此类。它是所有块/原语的基类。
FuzzableBlock
设计为具有子元素的可模糊类型。
FuzzableBlock重写以下方法,更改基于FuzzableBlock的任何类型的默认行为:
mutations()
,遍历所有子节点产生的突变。num_mutations()
,对每个子节点表示的突变求和。encode()
,调用函数get_child_data()
.
FuzzableBlock添加了以下方法:
get_child_data()
,渲染并连接所有子节点。push()
,添加额外的子节点;通常只在内部使用。
4.7.静态协议定义,Static Protocol Definition
老式Spike样式的静态协议定义格式,请参阅静态协议定义函数。不在赘述了,推荐使用新的Protocol Definition,见4.6节。
4.8.其他模块,Other Modules
4.8.1.测试用例会话引用,ProtocolSessionReference
指在单个测试用例的上下文中接收或生成的动态值。
将此对象作为原语的default_value
参数传递,并确保使用回调设置引用的值,例如,post_test_case_callbacks
(请参阅Session
)
4.8.2.ProtocolSession
包含一个session_variables
字典,用于存储特定于单个模糊测试用例的数据。
通常,session_variables
中的值将在回调函数中设置,例如,post_test_case_callbacks
(请参阅Session
)。
变量可以在以后的回调函数中使用,也可以由ProtocolSessionReference
对象使用。
4.8.3.Helpers
该类包含了许多助手函授和小工具,熟悉它们,让你更加得心应手。
4.8.4.IP Constants
此文件包含IPv4协议的常量。
在版本0.2.0中更改:ip_constants
已移动到connections子包中。完整路径现在是boofuzz.connections.ip_constants
4.8.5.PED-RPC
Boofuzz提供了一个RPC原语来在远程机器上托管监控器。主boofuzz实例充当连接到(远程)运行的RPC服务器实例的客户端,透明地调用在服务器实例的客户端实例上调用的函数,并将其结果作为python对象返回。一般来说,通过RPC接口传递的数据需要能够被pickle。
请注意,PED-RPC不提供任何形式的身份验证或授权。建议仅在受信任的网络上运行它。
4.8.6.DCE-RPC
期待更新…
4.8.7.Crash binning
期待更新…
4.8.8.EventHook
期待更新…
参考
项目github地址,https://github.com/jtpereyda/boofuzz
boofuzz手册,https://boofuzz.readthedocs.io/en/stable/
IoT 设备网络协议模糊测试工具boofuzz实战,https://blog.csdn.net/song_lee/article/details/104334096
Practical Modbus Fuzzing with boofuzz,https://64k.space/practical-modbus-fuzzing-with-boofuzz.html
以上是关于Boofuzz协议漏洞挖掘入门教程与使用心得的主要内容,如果未能解决你的问题,请参考以下文章
第12阶段 SRC安全应急响应中心漏洞挖掘视频教程第七期课程 18.逻辑漏洞与SRC挖掘经验
第12阶段 SRC安全应急响应中心漏洞挖掘视频教程第七期课程 11.CSRF漏洞与SRC挖掘经验
第12阶段 SRC安全应急响应中心漏洞挖掘视频教程第七期课程 6.XSS漏洞基础与SRC漏洞经验 7.SQL注入基础与SRC漏洞经验