数据包嗅探和伪造实验
完成条件
1 Scapy 中的 TCP/IP 类
对于 TCP/IP 中的每个协议,Scapy 都定义了一个对应的类,包括 Ether
, ARP
, IP
, ICMP
, TCP
, UDP
, DNS
等等。要构造数据包的头部,我们需要知道每个头部字段的名字。可以使用 ls
函数找到这些名字。
以下是一个示例,它列出了 IP 头部的所有字段名(第三列表示未设置值时使用的默认值):
$ python3
>>> from scapy.all import *
>>> ls(IP)
version : BitField (4 bits) = (4)
ihl : BitField (4 bits) = (None)
tos : XByteField = (0)
len : ShortField = (None)
id : ShortField = (1)
flags : FlagsField (3 bits) = (<Flag 0 ()>)
frag : BitField (13 bits) = (0)
ttl : ByteField = (64)
proto : ByteEnumField = (0)
chksum : XShortField = (None)
src : SourceIPField = (None)
dst : DestIPField = (None)
options : PacketListField = ([])
2 获取每层的信息
每个数据包都有多个层。给定一个数据包,我们经常需要访问该数据包中的某个特定层。了解 Scapy 如何组织这些层可以帮助我们更好地理解如何访问这些层。以下示例首先创建了一个由 Ethernet、IP、UDP 和数据层组成的数据包。
>>> pkt = Ether()/IP()/UDP()/"hello"
>>> pkt
<Ether type=IPv4 |<IP frag=0 proto=udp |<UDP |<Raw load='hello' |>>>
每个层的数据部分包含整个下一层,该层由一个对象表示。在 Scapy 中,数据部分的字段名称为 payload
。在我们的例子中,该数据包是一个 Ether
对象。其 payload
字段是 IP 对象。IP 对象的 payload
字段是 UDP 对象,而 UDP 对象的 payload
字段是 Raw 对象。最后,Raw对象的 load
字段是实际负载,即字符串 "hello"。
>>> pkt.payload 🢀 一个 IP 对象
<IP frag=0 proto=udp |<UDP |<Raw load='hello' |>>
>>> pkt.payload.payload 🢀 一个 UDP 对象
<UDP |<Raw load='hello' |>>
>>> pkt.payload.payload.payload 🢀 一个 Raw 对象
<Raw load='hello' |>
>>> pkt.payload.payload.payload.load 🢀 实际负载
b'hello'
以这种方式访问层将非常繁琐。Scapy 为每个协议类实现了一个名为 getlayer()
的函数,帮助我们获取内层的对象。我们也可以使用数组索引来获取内层对象(实际也是调用了这个函数)。见以下示例。
>>> pkt.getlayer(UDP)
<UDP |<Raw load='hello' |>>
>>> pkt[UDP]
<UDP |<Raw load='hello' |>>
>>> pkt.getlayer(Raw)
<Raw load='hello' |>
>>> pkt[Raw]
<Raw load='hello' |>
如果想检查某个内层是否存在,可以调用 haslayer()
,见以下示例。
>>> pkt.haslayer(UDP)
True
>>> pkt.haslayer(TCP)
0
>>> pkt.haslayer(Raw)
True
内容来源:书, Network Security Basics,ch 6
最后修改: 2025年09月8日 星期一 15:55