" 网络神器 " scapy
是 python 的一个第三方模块,能够发送、捕获、分析和铸造网络数据包
主要功能:扫描、识别、测试、攻击、包铸造、抓包分析
from scapy.all import *
from scapy.layers.inet import *
pkt = IP()/TCP()
# 该包的结构包含 IP 部分和 TCP 部分
构造数据包
pkt = IP(src="10.9.47.66",dst="10.6.47.88")/TCP()
OSI 模型中的下层协议在前,以/
隔开
Ether()/IP()/TCP()
Ether 类用于设置发送方和接收方的 MAC 地址
pkt=IP()/TCP()/"GET / HTTP1.0\r\n\r\n"
pkt=IP(dst="192.168.147.215")/ICMP()
res=sr1(pkt)
res.show()
pkt=IP()/TCP()
pkt.show()
显示的内容
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = tcp
chksum = None
src = 127.0.0.1
dst = 127.0.0.1
\options \
###[ TCP ]###
sport = ftp_data
dport = http
seq = 0
ack = 0
dataofs = None
reserved = 0
flags = S
window = 8192
chksum = None
urgptr = 0
options = ''
pkt=IP()/TCP()
ls(pkt)
显示的内容
version : BitField (4 bits) = 4 ('4')
ihl : BitField (4 bits) = None ('None')
tos : XByteField = 0 ('0')
len : ShortField = None ('None')
id : ShortField = 1 ('1')
flags : FlagsField = <Flag 0 ()> ('<Flag 0 ()>')
frag : BitField (13 bits) = 0 ('0')
ttl : ByteField = 64 ('64')
proto : ByteEnumField = 6 ('0')
chksum : XShortField = None ('None')
src : SourceIPField = '127.0.0.1' ('None')
dst : DestIPField = '127.0.0.1' ('None')
options : PacketListField = [] ('[]')
--
sport : ShortEnumField = 20 ('20')
dport : ShortEnumField = 80 ('80')
seq : IntField = 0 ('0')
ack : IntField = 0 ('0')
dataofs : BitField (4 bits) = None ('None')
reserved : BitField (3 bits) = 0 ('0')
flags : FlagsField = <Flag 2 (S)> ('<Flag 2 (S)>')
window : ShortField = 8192 ('8192')
chksum : XShortField = None ('None')
urgptr : ShortField = 0 ('0')
options : TCPOptionsField = [] ("b''")
发送数据包的函数 | 说明 |
---|---|
sr(pkt) | 发送数据包,接收所有返回包 返回值时两个列表,第一个列表包含收到了应答的数据包和对应的数据包 第二个列表包含未收到应答的数据包 |
sr1(pkt) | 发送数据包,接收一个返回包 |
send(pkt) | 发送数据包,不等待返回包 |
srp(pkt) | 发送2 层数据包,等待回应 |
sendp(pkt) | 发送2 层数据包,不等待返回包 |
sr()
from scapy.all import *
from scapy.layers.inet import *
pkt=IP(dst="192.168.147.215")/ICMP()
res,unres=sr(pkt)
res.summary()
# 接收到应答包的数据包和返回包保存到了 res 列表中,使用 res.summary() 可查看两个数据包中的内容
# 未接收到应答的数据包保存到 unres 列表中
send()
from scapy.all import *
from scapy.layers.inet import *
pkt=IP(dst="192.168.147.215")/ICMP()
print(pkt.summary())
send(pkt)
from scapy.all import *
from scapy.layers.inet import *
pkt=Ether(dst="ff:ff:ff:ff:ff:ff")
print(pkt.summary())
sendp(pkt)
res.show()
from scapy.all import *
from scapy.layers.inet import *
pkt=IP(dst="192.168.147.215")/ICMP()
res=sr1(pkt)
res.show()
res.type
(回复的 ICMP 数据包的类型编号及含义)
类型(十进制) | 内容 |
---|---|
0 | 回送应答 |
3 | 目标不可达 |
4 | 原点抑制 |
5 | 重定向或改变路由 |
8 | 回送请求 |
9 | 路由器公告 |
10 | 路由器请求 |
11 | 超时 |
17 | 地址子网请求 |
18 | 地址子网应答 |
函数名 | 用途 |
---|---|
lsc() | 查看常用函数及其使用方法 |
raw() | 以字节格式显示数据包内容raw(pkt) |
hexdump() | 以十六进制数据表示数据包中的内容hexdump(pkt) |
summary() | 使用不超过一行的摘要内容来简单描述数据包pkt.summary() |
show() | 显示数据包的详细信息pkt.show() |
show2() | 相比于 show() 增加了显示数据包的校验和 |
command() | 显示出构造该数据包的命令res.command() |
wrpcap() | 将数据包存储在文件中wrpcap("tmp.cap",pkts) |
rdpcap() | 读取 .cap 文件中的数据包(注意格式为列表)pkts=rdpcap(temp.cap) |
pkt=IP()/TCP()
print(raw(pkt))
pkt=IP()/TCP()
print(hexdump(pkt))
pkt=IP()/TCP()
print(pkt.summary())
pkt=IP(src="192.168.147.238",dst="192.168.147.215")
res=sr1(pkt)
print(res.command())
使用wrpcap()
函数存储时,可以将多个 pkt 使用存储为一个列表
使用rdpcap()
函数读取数据包时注意为列表格式
from scapy.all import *
from scapy.layers.inet import *
# IP(src="192.168.147.238",dst="192.168.147.215")
pkt1=IP(src="192.168.147.238",dst="192.168.147.215")/TCP()
pkt2=IP()/ICMP()
pkts=[pkt1,pkt2]
# 将数据包列表 pkts 存储在文件中
wrpcap("temp.cap",pkts)
# 读取存储数据包的文件(列表格式)
pkt_list=rdpcap("temp.cap")
# 第一个数据包的摘要
print(pkt_list[0].summary())
# 第二个数据包的详细数据
print(pkt_list[1].show())
参数名 | 含义 |
---|---|
filter | 指定捕获数据包的过滤条件,例如指定捕获特定端口、特定协议等 如 dst host 192.168.1.1 and port 8080 |
iface | 指定要使用的网卡,默认为第一个网卡 |
prn | 指定一个回调函数,用于处理捕获到的每个数据包 |
count | 指定捕获的数据包数量 |
采用伯克利包过滤机制
限定符 | 解释 |
---|---|
Type | 表示指代的对象 如 IP 地址(host)、子网(net)或端口P(port)等 默认为 host |
Dir | 表示数据包的传输方向 常见 scr(源地址)、dst(目的地址) 默认为 “scr or dst” |
Proto | 便是数据包匹配的协议类型 常见 Ether、IP、TCP、ARP |
过滤语句举例:
host 192.168.1.1
dst host 192.168.1.1
src port 8080
# 以太网(MAC 地址)源地址或者目的地址为 11:22:33:44:55:66
ether host 11:22:33:44:55:66
# 源 MAC 为 11:22:33:44:55:66 的数据包
ether src 11:22:33:44:55:66
# 源地址在 192.168.1.0/24 网段的数据包
src net 192.168.1.0/24
# 还可以使用 and、or、not 组合过滤
host 192.168.1.1 and port 8080
from scapy.all import *
# 定义一个回调函数,输出数据包的概述
def callback(pkt):
print(pkt.summary)
sniff(filter="icmp and host 192.168.147.215",iface="eth0",prn=callback,count=3)
# 过滤 192.168.147.215 的 icmp 报文
# 选择监听 eth0 网卡
# 指定定义好的回调函数 sniff
# 捕获三个数据包
运行后,开始监听
此时,ping 过滤的主机,即可捕获到数据包