在前两篇博客中,笔者简单分享了如何使用scapy进行网络流量的分析,但比较粗略,没有详细说明,本文我们就0开始,一起快速学习一下scapy 框架的使用。
另附之前的两篇博客,有需要快速参考代码的请自取:
使用Scapy框架分析HTTP流量
使用 Scapy 分析网络包:Python 网络编程的利器
Scapy
Scapy is a powerful interactive packet manipulation library written in Python. Scapy is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more.
根据官方的说法, scapy的功能是 “packets manipulation in Python”,即用python操控packet, 这个说法相当贴切。
对于python的版本是有要求的,当前是需要高于 python 3.7.
安装
可以用pip非常方便的安装
pip install scapy
同时可以clone代码
git clone --depth 1 https://github.com/secdev/scapy
cd scapy
sudo ./run_scapy

应用
下面我们通过一些具体的例子快速学习框架的使用
操作packet
scapy中有一个特殊的运算符/,作用是 “stack packets”,把packet堆叠起来.
我们实际操作一下。
>>> packet = IP()/TCP()
>>> Ether()/packet
输出
<Ether type=IPv4 |<IP frag=0 proto=tcp |<TCP |>>>
还可以列出packet中的字段,用ls方法
>>> ls(IP,verbose=True)
version : BitField (4 bits) = ('4')
ihl : BitField (4 bits) = ('None')
tos : XByteField = ('0')
len : ShortField = ('None')
id : ShortField = ('1')
flags : FlagsField = ('<Flag 0 ()>')MF, DF, evil
frag : BitField (13 bits) = ('0')
ttl : ByteField = ('64')
proto : ByteEnumField = ('0')
chksum : XShortField = ('None')
src : SourceIPField = ('None')
dst : DestIPField = ('None')
options : PacketListField = ('[]')
并且通过scapy,访问堆叠后的packet字段也非常方便
>>> p = Ether()/IP(dst="www.baidu.com")/TCP(flags="F")
>>> p.summary()
'Ether / IP / TCP 192.168.3.176:ftp_data > Net("www.baidu.com/32"):http F'
>>> print(p.dst)
88:44:77:be:33:41
>>> print(p[IP].src)
192.168.3.176
并且,在一个字段中,可以是有多个值的,通过遍历可以取出
>>> [p for p in IP(ttl=(1,5)) / ICMP()]
[<IP frag=0 ttl=1 proto=icmp |<ICMP |>>,<IP frag=0 ttl=2 proto=icmp |<ICMP |>>,<IP frag=0 ttl=3 proto=icmp |<ICMP |>>,<IP frag=0 ttl=4 proto=icmp |<ICMP |>>,<IP frag=0 ttl=5 proto=icmp |<ICMP |>>]
网络交互
我们用一个DNS查询作为例子展现网络交互. 网络交互的时候,通常会用到一个方法sr1,注意这里是自然数1,不是字母l.
构造并发送数据包:
>>> dns_req=IP(dst="8.8.8.8")/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname='baidu.com')
...: )
>>> answer = sr1(dns_req,verbose=0)
>>> print(answer[DNS].an)
[<DNSRR rrname='baidu.com.' type=A rclass=IN ttl=484 rdata=39.156.66.10 |>, <DNSRR rrname='baidu.com.' type=A rclass=IN ttl=484 rdata=110.242.68.66 |>]
IP(dst="8.8.8.8"):构造一个IP层,目标地址设为8.8.8.8,这是Google的公共DNS服务器。UDP():构造一个UDP层。DNS():构造一个DNS层,默认是一个空的DNS查询。IP() / UDP() / DNS():这三个层级的协议组合成一个完整的数据包。sr1():发送这个数据包并等待一个响应包。sr1函数会返回收到的第一个响应数据包。
提取DNS响应:
answer[DNS].an
answer是响应的数据包。answer[DNS]:从响应数据包中提取DNS层。answer[DNS].an:提取DNS层中的答案部分(an表示answer)。
通过这段代码,你可以发送一个简单的DNS查询请求到8.8.8.8,并获取这个请求的响应包,然后从响应包中提取DNS的答案部分。如果DNS查询成功并且有答案,这个部分将包含DNS响应的详细信息,如域名对应的IP地址等。如果没有答案,answer[DNS].an可能为None。
可视化
scapy支持plot图形,可以方便我们进行可视化分析,下面我们看一个可视化的例子,为了方便输出图片,我们用jupyter.
# import所需要的包
from scapy.all import *
我们需要用srloop这个方法
srloop: Send a packet at layer 3 in loop and print the answer each time
ans, unans = srloop(IP(dst=["8.8.8.8", "8.8.4.4"]) / ICMP(), inter=.1, timeout=.1, count=100, verbose=False)
这段代码的主要功能是发送ICMP(Internet Control Message Protocol,互联网控制消息协议)包到指定的IP地址,然后接收返回的包。
解释如下:
-
IP(dst=["8.8.8.8", "8.8.4.4"]) / ICMP():这部分代码创建了一个ICMP包,目标IP地址是"8.8.8.8"和"8.8.4.4"。/操作符在Scapy中用来组合多个网络层的包。 -
srloop(...):这是Scapy的一个函数,用来发送包并接收响应。它会持续发送网络包,直到满足一定的条件。 -
inter=.1:这是发送包之间的时间间隔,单位是秒。这里设置为0.1秒。 -
timeout=.1:这是等待响应的超时时间,单位是秒。这里设置为0.1秒。 -
count=100:这是发送包的数量。 -
verbose=False:这是一个选项,决定是否打印详细的操作信息,设置为False则不打印。
最后,srloop函数返回两个值:ans和unans。ans是一个列表,包含了接收到的响应包。unans也是一个列表,包含了没有接收到响应的包。
然后我们进行可视化
%matplotlib inline
ans.multiplot(lambda x_y: (x_y[1][IP].src, (x_y[1].time, x_y[1][IP].id)), plot_xy=True)
输出效果如下图所示

小结
本文介绍了scapy的安装使用,并通过例子给出了scapy强大功能的直接展现,希望本文能够帮助大家快速入门这个优秀的网络分析库,欢迎交流