第1章:Python模糊测试框架搭建
各位同学好,我是老周。在电信核心网干了十几年协议测试,今天咱们聊聊怎么搭一套趁手的模糊测试环境。说实话,很多新手一上来就想着跑大型工具,结果环境配三天,跑起来五分钟就崩了——这种事我见得太多了。
这一章,咱们从零开始,把Python环境、Scapy、Boofuzz这些基础工具捋一遍。最后我会带大家写一个最简单的自定义Fuzzer。嗯,别急,一步步来。
1.1 Python环境配置
我个人习惯用Python 3.8到3.10之间的版本。为什么?因为Scapy和Boofuzz在这些版本上最稳定。我曾经在Python 3.11上踩过坑,某些依赖库的二进制包还没跟上,折腾了半天。
建议用虚拟环境隔离项目,别把系统Python搞乱了。
推荐配置:
- Python 3.9.13(我目前的主力版本)
- pip 23.0+
- virtualenv 或 conda 管理环境
# 创建虚拟环境
python -m venv fuzz_env
# 激活(Linux/Mac)
source fuzz_env/bin/activate
# 激活(Windows)
fuzz_env\Scripts\activate
# 升级pip
pip install --upgrade pip
小技巧: 我习惯在项目根目录放一个 requirements.txt,把所有依赖写进去。这样换机器时一行命令就能恢复环境。
1.2 Scapy库安装与基础使用
Scapy是协议模糊测试的瑞士军刀。说白了,它能让你像搭积木一样构造任意协议报文。我当年第一次用Scapy构造SIP消息时,感觉打开了新世界的大门。
安装
pip install scapy
装完验证一下:
python -c "from scapy.all import *; print('Scapy OK')"
基础用法
咱们先构造一个最简单的IP包。你想想看,核心网里跑的全是IP报文,这个基础必须打牢。
from scapy.all import *
# 构造一个IP包
pkt = IP(src="192.168.1.1", dst="10.0.0.1")/TCP(sport=1234, dport=5060)
pkt.show()
# 发送并接收响应
ans = sr1(pkt, timeout=2)
if ans:
ans.show()
为什么会这样设计?Scapy用 / 操作符把协议层叠起来,非常直观。我在项目中经常用这个特性快速构造畸形报文——比如把IP头的 ihl 字段改成0,看看对端会不会崩溃。
注意: 发送原始报文需要root/管理员权限。我在Windows上吃过这个亏,折腾了半天才发现是权限问题。
1.3 Boofuzz框架入门
Boofuzz是Sulley的继承者,专门做协议模糊测试。我个人觉得它最大的优点是:你只需要定义协议结构,它自动帮你生成变异数据。
安装
pip install boofuzz
一个简单的例子
咱们用Boofuzz测试一个简单的TCP服务。假设目标监听在 127.0.0.1:8888。
from boofuzz import *
def test_tcp():
session = Session(
target=Target(connection=TCPSocketConnection("127.0.0.1", 8888))
)
# 定义协议结构
s_initialize("TestPacket")
s_static("HELO") # 固定头部
s_delim(" ") # 分隔符
s_string("FUZZ", fuzzable=True) # 模糊字段
s_static("\r\n") # 结束符
session.connect(s_get("TestPacket"))
session.fuzz()
if __name__ == "__main__":
test_tcp()
这段代码里,s_string("FUZZ", fuzzable=True) 告诉Boofuzz:这个字段可以随便改。它会自动生成超长字符串、特殊字符、边界值等测试用例。
核心概念:
- Session:管理整个测试流程
- Target:定义被测目标
- s_initialize:初始化一个协议模板
- s_static/s_string:定义固定字段和可变字段
1.4 自定义Fuzzer编写基础
有时候现成的框架不够灵活,比如你想针对某个协议字段做特殊变异。这时候就得自己写Fuzzer了。别怕,其实核心逻辑很简单:构造报文 → 发送 → 监控响应。
下面是我写的一个最小化Fuzzer模板,你可以在此基础上扩展。
import socket
import random
from scapy.all import *
class SimpleFuzzer:
def __init__(self, target_ip, target_port):
self.target_ip = target_ip
self.target_port = target_port
self.sock = None
def connect(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(5)
self.sock.connect((self.target_ip, self.target_port))
def generate_payload(self):
"""生成随机载荷"""
length = random.randint(1, 100)
return bytes([random.randint(0, 255) for _ in range(length)])
def send_payload(self, payload):
try:
self.sock.send(payload)
response = self.sock.recv(1024)
return response
except Exception as e:
print(f"发送失败: {e}")
return None
def fuzz(self, count=100):
print(f"开始模糊测试 {self.target_ip}:{self.target_port}")
for i in range(count):
payload = self.generate_payload()
print(f"[{i+1}/{count}] 发送 {len(payload)} 字节")
resp = self.send_payload(payload)
if resp:
print(f"收到响应: {len(resp)} 字节")
else:
print("无响应或连接断开")
# 重新连接
self.connect()
self.sock.close()
# 使用示例
if __name__ == "__main__":
fuzzer = SimpleFuzzer("127.0.0.1", 8888)
fuzzer.connect()
fuzzer.fuzz(50)
这段代码虽然简单,但包含了Fuzzer的核心要素:
- 连接管理:建立和断开socket
- 载荷生成:随机数据生成器
- 发送与监控:发送数据并捕获响应
- 异常处理:连接断开后自动重连
避坑指南: 我曾经犯过一个错误——没有处理连接断开的情况。结果测试跑到一半,程序卡死在 recv() 上。后来我加上了超时和重连机制,才稳定下来。
知识体系总览
下面这张图概括了本章的核心内容。你可以把它当作搭建模糊测试环境的路线图。
这张图展示了从环境搭建到实战应用的完整路径。每一步都是下一层的基础,缺一不可。我个人建议你按照这个顺序来学习,别跳步。
本章小结:
- Python环境用虚拟环境隔离,版本选3.9左右最稳
- Scapy是构造协议报文的神器,
/操作符要熟练 - Boofuzz适合自动化测试,定义好协议结构就能跑
- 自定义Fuzzer的核心是:构造→发送→监控→重连
好了,这一章的内容就到这里。环境搭好了,下一章咱们就开始玩真的——用Scapy构造SIP协议报文,看看核心网设备会有什么反应。