Commit a491e6ba by 文周繁

feat:修改s2fuzzer说明文档

parent 7681ccd6
# S2fuzzer说明 # S2fuzzer说明
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
## 工具简介 ## 工具简介
`s2fuzzer`是一款针对网络协议程序的模糊测试工具,它基于`stateafl`模糊测试器,并在此基础上进行了创新性的扩展。工具通过引入共享内存来替换原始的网络I/O接口来传输网络协议数据包,实现执行速率的提升,从而发现更多潜在的安全漏洞;同时实现针对无源码网络协议二进制程序的插桩,从而对无源码网络协议二进制程序开展灰盒模糊测试。 `s2fuzzer`是一款针对网络协议程序的模糊测试工具,它基于`StateAFL`模糊测试器,并在此基础上进行了创新性的扩展。工具通过引入共享内存来替换原始的网络I/O接口来传输网络协议数据包,实现执行速率的提升,从而发现更多潜在的安全漏洞;同时实现针对无源码网络协议二进制程序的插桩,从而对无源码网络协议二进制程序开展灰盒模糊测试。
...@@ -20,15 +20,15 @@ ...@@ -20,15 +20,15 @@
##### 1.2.1 基于共享内存的高效传输技术 ##### 1.2.1 基于共享内存的高效传输技术
为了实现基于共享内存的消息传输,通过分析测试程序收集网络 I/O 接口相关的库函数,hook 相关的库函数干预客户端与服务器之间的消息传输。收集程序中的网络套接字接口相关的库函数如 `send/recv``sendto/recvfrom`,以及读 / 写文件描述符的函数如 `write/read`,因为套接字就是文件描述符,也可通过读 / 写文件描述符的函数来进行数据传输。hook 以上网络传输相关的库函数,来干预客户端与服务器之间的消息交互传输,并设计客户端与服务器之间基于共享内存的数据交互传输函数,来替换原始程序中相关的套接字传输的库函数。 为了实现基于共享内存的消息传输,通过分析测试程序收集网络 I/O 接口相关的库函数,hook 相关的库函数干预客户端与服务器之间的消息传输。收集程序中的网络套接字接口相关的库函数如 `send/recv``sendto/recvfrom`,以及读 / 写文件描述符的函数如 `write/read`。hook 以上网络传输相关的库函数,来干预客户端与服务器之间的消息交互传输,并设计客户端与服务器之间基于共享内存的数据交互传输函数,来替换原始程序中相关的套接字传输的库函数。
![image-20250624093155032](./images/image-20250624093155032-1750818033311-1.png) ![image-20250624093155032](./images/image-20250624093155032-1750818033311-1.png)
##### 1.2.2 基于共享内存的会话状态传输技术 ##### 1.2.2 基于共享内存的会话状态同步技术
在实际模糊测试时,由于模糊测试器并不知道 `SUT` 是否准备好发送或接收信息,网络协议模糊测试器如 `AFLNet``StateAFL``send()/recv()`之前使用 `poll()`和手动设置超时阈值来处理这个问题。但这种模式下,如果设置的超时时间过长会给模糊测试迭代带来了额外的时间延迟,如果设置得过短,则会导致有状态模糊测试器可能会与其状态机不同步。上述问题的根本原因是通信双方,即客户端和服务器端,无法预测对方下一步计划做什么。 在实际模糊测试时,由于模糊测试器并不知道 `SUT(server under test)` 是否准备好发送或接收信息,网络协议模糊测试器如 `AFLNet``StateAFL`在每轮测试过程中,一般在发送两个不同的数据包之间手动设置一个固定等待时间。但这种模式下,如果设置的超时时间过长会给模糊测试迭代带来了额外的时间延迟,如果设置得过短,则会导致有状态模糊测试器可能会与其状态机不同步。上述问题的根本原因是通信双方,即客户端和服务器端,无法预测对方下一步计划做什么。
为了解决这个问题,将会话状态引入到方案中,会话状态也存储在共享内存中。会话状态可以是 C 或 S,状态 C 表示客户端正在发送或接收消息,如果服务器即将发送或接收消息,则应该阻塞。类似地,状态 S 表示服务器正在发送或接收消息,如果客户端即将发送或接收消息,则也应该阻塞。一旦任何一方完成了当前的任务,或者无法继续运行,它应该更改会话状态,以通知另一方执行下一个任务。这个动作实际上就是状态迁移,整个交互过程中,用于同步的会话状态迁移也可以用状态转换图来表示,如下图: 为了解决上述的问题,设计基于共享会话状态的同步机制。通过在共享内存中存储一个状态量,通信双方在完成相应网络 I/O 操作后,设置状态量来通知对方进行下一步的操作,实现双方交互的同步。会话状态可以是 C 或 S,状态 C 表示客户端正在发送或接收消息,如果服务器即将发送或接收消息,则应该阻塞。类似地,状态 S 表示服务器正在发送或接收消息,如果客户端即将发送或接收消息,则也应该阻塞。一旦任何一方完成了当前的任务,或者无法继续运行,它应该更改会话状态,以通知另一方执行下一个任务。这个动作实际上就是状态迁移,整个交互过程中,用于同步的会话状态迁移也可以用状态转换图来表示,如下图:
![image-20250624093035961](./images/image-20250624093035961-1750759463479-2.png) ![image-20250624093035961](./images/image-20250624093035961-1750759463479-2.png)
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#### 2.2 实现 #### 2.2 实现
`s2fuzzer` 通过在接收-处理-回复循环的每次迭代时检查进程内存的内容来推断当前的协议状态。当前的协议状态必然存储在数据结构中,例如堆和栈内存中,这些结构在每个请求-回复交换时更新。协议状态由**长期存在的数据**表示,其生命周期跨越单个请求-回复交换,并跨越整个会话。此类数据的例子包括客户端的当前认证状态、当前工作目录以及待处理的输入队列。相反,**短期存在的数据**具有较短的生命周期,因为它们仅存储一个或几个请求-回复交换所需的数据。`s2fuzzer` 跟踪整个会话中长期存在的数据结构的演变,并丢弃短期存在的数据。当成功达到一个新的协议状态时,新状态会导致长期数据结构的内容发生变化。因此,在每次请求-回复交换结束时获取此类数据的快照。然后,通过使用模糊哈希将每个唯一的内存状态映射到唯一的状态标识符,将此快照作为当前协议状态的代理。 `s2fuzzer` 通过在接收-处理-回复循环的每次迭代时检查进程内存的内容来推断当前的协议状态。当前的协议状态必然存储在数据结构中,这些结构在每个请求-回复交换时更新。协议状态由**长期存在的数据**表示,其生命周期跨越单个请求-回复交换,并跨越整个会话。此类数据的例子包括客户端的当前认证状态、当前工作目录以及待处理的输入队列。相反,**短期存在的数据**具有较短的生命周期,因为它们仅存储一个或几个请求-回复交换所需的数据。`s2fuzzer` 跟踪整个会话中长期存在的数据结构的演变,并丢弃短期存在的数据。当成功达到一个新的协议状态时,新状态会导致长期数据结构的内容发生变化。因此,在每次请求-回复交换结束时获取此类数据的快照。然后,通过使用哈希将每个唯一的内存状态映射到唯一的状态标识符,将此快照作为当前协议状态的代理。
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#### 3.1 定义 #### 3.1 定义
静态二进制重写是指在不执行程序的情况下,对目标程序(通常是已编译好的可执行文件)的二进制代码进行修改。这种技术通常用于安全加固、功能增强、代码优化等目的。它的核心在于分析和修改目标程序的机器码,使其行为发生变化,而无需访问源代码。`s2fuzzer`通过`Ghidra`对无源码网络协议二进制程序进行**静态分析**获取插桩辅助信息,随后二进制重写器 `E9Patch`对目标插桩指令通过重写写入插桩功能函数,实现对无源码网络协议二进制程序的插桩,从而对无源码网络协议二进制程序开展灰盒模糊测试。 静态二进制重写是指在不执行程序的情况下,对目标程序(通常是已编译好的可执行文件)的二进制代码进行修改。这种技术通常用于安全加固、功能增强、代码优化等目的。它的核心在于分析和修改目标程序的机器码,使其行为发生变化,而无需访问源代码。`s2fuzzer`通过`Ghidra`对无源码网络协议二进制程序进行**静态分析**获取插桩辅助信息,随后二进制重写器 `E9Patch`对目标插桩指令通过重写写入插桩功能函数,实现对无源码网络协议二进制程序的插桩,插入覆盖率及状态码信息,从而对无源码网络协议二进制程序开展灰盒模糊测试。
#### 3.2 实现 #### 3.2 实现
...@@ -92,17 +92,19 @@ make ...@@ -92,17 +92,19 @@ make
编译完成后,工具目录生成如下程序: 编译完成后,工具目录生成如下程序:
| 名称 | 说明 | | 名称 | 说明 |
| :-----------------: | :--------------------------: | | :-----------------: | :----------------------------: |
| afl-clang-fast | 高性能`Clang`封装器 | | afl-clang-fast | 高性能`Clang`封装 |
| afl-clang-fast++ | 高性能`Clang++`封装器 | | afl-clang-fast++ | 高性能`Clang++`封装 |
| s2fuzzer | 模糊测试主引擎 | | s2fuzzer | 模糊测试主引擎 |
| aflnet-replay | 有状态网络协议重放器 | | aflnet-replay | 有状态网络协议重放器 |
| afl-llvm-pass.so | `LLVM`插桩插件 | | afl-llvm-pass.so | `LLVM`插桩插件 |
| sock2shm.so | 共享内存加速库 | | sock2shm.so | 共享内存加速库 |
| e9tool | `E9Patch` 的线性反汇编工具 | | state-tracer-log.so | 状态推断函数库 |
| testghidra | java实现的`Ghidra`脚本工具集 | | afl-rt-bk-2.o | 插桩函数中间件 |
| state-tracer-log.so | 状态推断函数库 | | ghidrascript | `java`实现的`Ghidra`脚本工具集 |
### 2.工具参数说明 ### 2.工具参数说明
...@@ -129,7 +131,8 @@ make ...@@ -129,7 +131,8 @@ make
一般情况下,可以通过以下命令启动对一个server的协议模糊测试:
一般情况下,可以通过以下命令启动对一个server的协议模糊测试:
```sh ```sh
s2fuzzer -d -i in -o out -N <server info> -x <dictionary file> -P <protocol> -D 10000 -q 3 -s 3 -E -K -R <executable binary and its arguments (e.g., port number)> s2fuzzer -d -i in -o out -N <server info> -x <dictionary file> -P <protocol> -D 10000 -q 3 -s 3 -E -K -R <executable binary and its arguments (e.g., port number)>
...@@ -149,7 +152,7 @@ $ git clone https://github.com/CrowCpp/Crow ...@@ -149,7 +152,7 @@ $ git clone https://github.com/CrowCpp/Crow
$ cd Crow $ cd Crow
# 安装依赖 # 安装依赖
$ apt install libasio-dev $ apt install libasio-dev
# 设置编译器为高性能Clang封装器和高性能Clang++封装器 # 设置编译器为高性能Clang封装和高性能Clang++封装
$ cmake . build -DCMAKE_C_COMPILER=/path/to/s2fuzzer/afl-clang-fast -DCMAKE_CXX_COMPILER=/path/to/s2fuzzer/afl-clang-fast++ $ cmake . build -DCMAKE_C_COMPILER=/path/to/s2fuzzer/afl-clang-fast -DCMAKE_CXX_COMPILER=/path/to/s2fuzzer/afl-clang-fast++
$ make $ make
# 得到可执行程序/path/to/Crow/example/basic_example # 得到可执行程序/path/to/Crow/example/basic_example
...@@ -229,9 +232,9 @@ $ make ...@@ -229,9 +232,9 @@ $ make
##### 3.2.2 修改HelloIdeaGhidra.java ##### 3.2.2 修改GhidraCustomScript.java
修改`e9patch/testghidra/src/HelloIdeaGhidra.java`文件,将**192行****193行**修改为**自定义路径**,如下图: 修改`/path/to/e9patch/ghidrascript/src/GhidraCustomScript.java`文件,将**192行****193行**修改为**自定义路径**,如下图:
![](./images/截图 2025-06-23 18-17-09.png) ![](./images/截图 2025-06-23 18-17-09.png)
...@@ -265,21 +268,21 @@ $ make ...@@ -265,21 +268,21 @@ $ make
点击右上角`Manager Script Directories`,出现如下界面: 点击右上角`Manager Script Directories`,出现如下界面:
![image-20250529104727105](./images/image-20250529104727105.png) ![image-20250702085040208](./images/image-20250702085040208.png)
点击右上角`Display file chooseer to add bundles to list`,选择`testghidra/src`文件夹,点击`OK`,可以看到被正确添加到列表,如上图。
点击右上角`Display file chooseer to add bundles to list`,选择`ghidrascript/src`文件夹,点击`OK`,可以看到被正确添加到列表,如上图。
回到`Script Manager`窗口,下方`Filter`输入`HelloIdeaGhidra`,可以看到我们写的脚本文件,如下图:
![image-20250529105219398](./images/image-20250529105219398.png)
点击`Run script`按钮,会生成`HelloIdeaGhidra.java`中定义的文件(),如下图: 回到`Script Manager`窗口,下方`Filter`输入`GhidraCustomScript`,可以看到我们写的脚本文件,如下图:
![image-20250529105437755](./images/image-20250529105437755.png) ![image-20250701173708727](./images/image-20250701173708727.png)
点击`Run script`按钮,会生成`/path/to/ghidrascript/src/GhidraCustomScript.java`**192行****193行**定义的文件,如下图:
![image-20250701173208913](./images/image-20250701173208913.png)
##### 3.2.4 使用E9patch进行插桩 ##### 3.2.4 使用E9patch进行插桩
...@@ -299,7 +302,7 @@ $ make ...@@ -299,7 +302,7 @@ $ make
搭配`s2fuzzer`使用,在`e9patch`目录下,使用`e9tool`工具进行代码覆盖率插桩。 搭配`s2fuzzer`使用,在`e9patch`目录下,使用`e9tool`工具进行代码覆盖率插桩。
```bash ```bash
./e9tool -M 'plugin(e9AFLPlugin).match()' -P 'entry(random)@afl-rt-bk-2' ./二进制程序 -o ./插桩后的二进制程序 /path/to/e9patch/e9tool -M 'plugin(e9AFLPlugin).match()' -P 'entry(random)@afl-rt-bk-2' ./二进制程序 -o ./插桩后的二进制程序
``` ```
通过e9AFLPlugin代码中的match函数确定所有基本块的插桩点位,在所有的插桩点位插入afl-rt中的entry函数,每次调用时,输出信息如下: 通过e9AFLPlugin代码中的match函数确定所有基本块的插桩点位,在所有的插桩点位插入afl-rt中的entry函数,每次调用时,输出信息如下:
...@@ -344,7 +347,7 @@ memory_used = 4984KB ...@@ -344,7 +347,7 @@ memory_used = 4984KB
搭配`s2fuzzer`使用,在`e9patch`目录下,使用`e9tool`工具进行代码覆盖率+状态推断插桩。 搭配`s2fuzzer`使用,在`e9patch`目录下,使用`e9tool`工具进行代码覆盖率+状态推断插桩。
```bash ```bash
./e9tool -M 'plugin(e9AFLPlugin).match()' -P 'entry(random)@afl-rt-bk-2' \ /path/to/e9tool -M 'plugin(e9AFLPlugin).match()' -P 'entry(random)@afl-rt-bk-2' \
-M 'plugin(funcMatch).match()' -P 'state_tracer(state,asm,size,offset)@afl-rt-bk-2' \ -M 'plugin(funcMatch).match()' -P 'state_tracer(state,asm,size,offset)@afl-rt-bk-2' \
./二进制程序 -o ./插桩后的二进制程序 ./二进制程序 -o ./插桩后的二进制程序
``` ```
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment