Scapy 数据包构造分析教程
Scapy 是一款强大的 Python 交互式数据包处理工具,可以用于构造、发送、嗅探和解析网络数据包。它支持大量的网络协议,从以太网帧到应用层协议都可以自由操控。Scapy 在网络安全测试、协议分析、网络探测和教学研究中都有广泛应用。本文介绍 Scapy 的安装和常见用法,帮助你掌握这一网络分析利器。
一、安装 Scapy
# 使用 pip 安装
pip3 install scapy
# 安装可选依赖(图形化和加密支持)
pip3 install matplotlib pyx cryptography
# 安装系统工具
apt install tcpdump graphviz -y
# 启动 Scapy 交互模式
scapy
二、数据包构造基础
2.1 构造 IP 数据包
from scapy.all import *
# 构造 IP 数据包
ip_pkt = IP(dst="8.8.8.8")
ip_pkt.show()
# 构造 ICMP Ping 包
ping = IP(dst="8.8.8.8")/ICMP()
ping.show()
# 发送并接收回复
reply = sr1(ping, timeout=2)
if reply:
reply.show()
2.2 构造 TCP 数据包
# TCP SYN 包
syn = IP(dst="example.com")/TCP(dport=80, flags="S")
# 发送 SYN 并接收 SYN-ACK
syn_ack = sr1(syn, timeout=2)
# 构造带数据的 HTTP 请求
http_req = IP(dst="example.com")/TCP(dport=80, flags="PA")/"GET / HTTP/1.1
Host: example.com
"
2.3 构造 UDP 数据包
# DNS 查询
dns_query = IP(dst="8.8.8.8")/UDP(dport=53)/DNS(rd=1, qd=DNSQR(qname="example.com"))
response = sr1(dns_query, timeout=2)
# 解析 DNS 响应
if response and response.haslayer(DNS):
for i in range(response[DNS].ancount):
print(f"记录: {response[DNS].an[i].rdata}")
三、网络嗅探
# 嗅探 10 个数据包
packets = sniff(count=10)
packets.summary()
# 按条件过滤嗅探
tcp_packets = sniff(filter="tcp and port 80", count=20, timeout=30)
# 实时处理嗅探到的包
def packet_handler(pkt):
if pkt.haslayer(TCP):
src = pkt[IP].src
dst = pkt[IP].dst
sport = pkt[TCP].sport
dport = pkt[TCP].dport
print(f"{src}:{sport} -> {dst}:{dport}")
sniff(filter="tcp", prn=packet_handler, count=50)
# 保存抓包到 PCAP 文件
packets = sniff(count=100)
wrpcap("/tmp/capture.pcap", packets)
# 读取 PCAP 文件
packets = rdpcap("/tmp/capture.pcap")
packets.summary()
四、网络扫描
4.1 ARP 扫描
# 扫描本地网络
ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24"), timeout=2)
print("在线主机:")
for sent, received in ans:
print(f" {received.psrc} - {received.hwsrc}")
4.2 TCP 端口扫描
# SYN 扫描
target = "192.168.1.1"
ports = [22, 80, 443, 8080, 3306]
for port in ports:
pkt = IP(dst=target)/TCP(dport=port, flags="S")
resp = sr1(pkt, timeout=1, verbose=0)
if resp and resp.haslayer(TCP):
if resp[TCP].flags == 0x12: # SYN-ACK
print(f"端口 {port}: 开放")
# 发送 RST 关闭连接
send(IP(dst=target)/TCP(dport=port, flags="R"), verbose=0)
elif resp[TCP].flags == 0x14: # RST-ACK
print(f"端口 {port}: 关闭")
4.3 Traceroute
# TCP Traceroute
result, unans = traceroute("example.com", maxttl=20)
result.show()
# ICMP Traceroute
ans, unans = sr(IP(dst="example.com", ttl=(1,20))/ICMP(), timeout=2)
for sent, received in ans:
print(f"TTL {sent.ttl}: {received.src}")
五、高级用法
5.1 构造自定义协议
class CustomProtocol(Packet):
name = "CustomProtocol"
fields_desc = [
ByteField("version", 1),
ShortField("length", 0),
IntField("sequence", 0),
StrLenField("data", "", length_from=lambda pkt: pkt.length)
]
# 使用自定义协议
pkt = IP(dst="192.168.1.1")/UDP(dport=9999)/CustomProtocol(version=1, sequence=1, data="Hello")
pkt.show()
5.2 数据包修改和重放
# 读取 PCAP 并修改数据包
packets = rdpcap("/tmp/capture.pcap")
for pkt in packets:
if pkt.haslayer(IP):
# 修改源 IP
pkt[IP].src = "10.0.0.100"
# 重新计算校验和
del pkt[IP].chksum
if pkt.haslayer(TCP):
del pkt[TCP].chksum
# 重放修改后的数据包
sendp(packets, iface="eth0")
六、实用脚本示例
#!/usr/bin/env python3
"""网络连通性测试脚本"""
from scapy.all import *
import sys
def ping_test(target, count=5):
"""ICMP Ping 测试"""
print(f"Ping {target}:")
success = 0
for i in range(count):
reply = sr1(IP(dst=target)/ICMP(seq=i), timeout=2, verbose=0)
if reply:
rtt = (reply.time - reply.sent_time) * 1000
print(f" 回复来自 {reply.src}: 时间={rtt:.1f}ms TTL={reply.ttl}")
success += 1
else:
print(f" 请求超时")
print(f"统计: 发送={count}, 接收={success}, 丢失={count-success}")
if __name__ == "__main__":
target = sys.argv[1] if len(sys.argv) > 1 else "8.8.8.8"
ping_test(target)
七、注意事项
- Scapy 的大多数功能需要 root 权限,因为需要创建原始套接字。
- 在生产网络中谨慎使用扫描功能,可能触发安全告警。
- 端口扫描和数据包注入可能违反服务条款,请确保你有授权。
- 在搬瓦工 VPS 上使用时,避免对外部网络进行大规模扫描。
总结
Scapy 是网络安全和协议分析领域最灵活的工具之一,它将数据包处理的完整控制权交给用户。无论是学习网络协议、进行安全测试还是开发网络工具,Scapy 都是不可或缺的利器。配合 Ansible 和 NAPALM 可以构建更完整的网络自动化工具链。选购搬瓦工 VPS 请参考 全部方案,购买时使用优惠码 NODESEEK2026 可享受 6.77% 的优惠,通过 bwh81.net 进入官网购买。