Boofuzz协议漏洞挖掘入门教程与使用心得

文章目录

本文主要涉及到对Boofuzz的简单介绍,以及基于BoofuzzBoofuzz协议漏洞挖掘入门教程与使用心得
上图是Sulley的整体框架图,来源于Blmkdir boofuzz && cd boofuzz $ python3 -m venv env

这将在当前文件夹中创建一个新的虚拟环境env。请注意,虚拟环境中的Python版本是固定的,并在创建时选择。与全局安装不同,在虚拟环境中,python被别名为虚拟环境的python版本。

接下来,激活虚拟环境:

source env/bin/activate 

如果在windows平台上,使用命令:

envScriptsactivate.bat 

使用一下命令更pipsetuptools

(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接口。可用的子类包括:

3.2.定义消息(Request)

会话对象就绪后,接下来需要在协议中定义消息。

每个消息都是一个请求对象,其子对象定义该消息的结构。

以下是FTP协议中的几个消息定义:

user = Request("user", children=(     String("key", "USER"),     Delim("space", " "),     String("val", "anonymous"),     Static("end", "rn"), ))  passw = Request("pass", children=(     String("key", "PASS"),     Delim("space", " "),     String("val", "james"),     Static("end", "rn"), ))  stor = Request("stor", children=(     String("key", "STOR"),     Delim("space", " "),     String("val", "AAAA"),     Static("end", "rn"), ))  retr = Request("retr", children=(     String("key", "RETR"),     Delim("space", " "),     String("val", "AAAA"),     Static("end", "rn"), )) 

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)画出来,如下所示:

Boofuzz协议漏洞挖掘入门教程与使用心得

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上从进程收集调试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", "rn"),     )),     Block("Host-Line", children=(         String("Host-Key", "Host:"),         Delim("space", " "),         String("Host-Value", "example.com"),         Static("CRLF", "rn"),     )),     Static("CRLF", "rn"), )) 

    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("rn", 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("rn", name="Host-Line-CRLF")     s_static("rn", "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 + "x00x00",         "/.../.../.../.../.../.../.../.../.../.../",         "/../../../../../../../../../../../../boot.ini",         "/../../../../../../../../../../../../etc/passwd",         "/.:/" + "A" * 5000 + "x00x00",         "/\" * 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.制作自己的块/原语

    要创建自己的块/基本体,请执行以下操作:

    Overload,Override,Overwrite区别

    • Overload重载,同一个作用域中,语义功能相似,仅函数名相同;
    • Override覆盖,继承关系中,Override一般用于多态技术,函数必须实现基类的统一接口;
    • Overwrite重写,继承关系中,子类函数名与父类相同。
    • 可选:创建附带的静态原语函数。示例,请参见boofuzz的__init__.py文件。

    如果您的块依赖于对其他块的引用,那么校验和或长度字段依赖于消息的其他部分的方式,请参阅Size源代码以获取如何避免递归问题,并小心。

    Fuzzable

    自定义块/原语时,需要继承此类。它是所有块/原语的基类。

    FuzzableBlock

    设计为具有子元素的可模糊类型。

    FuzzableBlock重写以下方法,更改基于FuzzableBlock的任何类型的默认行为:

    1. mutations() ,遍历所有子节点产生的突变。
    2. num_mutations() ,对每个子节点表示的突变求和。
    3. encode() ,调用函数 get_child_data().

    FuzzableBlock添加了以下方法:

    1. get_child_data(),渲染并连接所有子节点。
    2. 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.