scapy是一个可用于网络嗅探的非常强大的第三方库
1.交互模式,可做第三方库
2.可以用来做packet嗅探和伪造packet
3.已经在内部实现了大量的网络协议.(DNS,ARP,TCP,UDP等等) 编写非常灵活实用的工具
该博客借鉴Scapy官方文档的中文翻译版 附上下载地址
https://legacy.gitbook.com/book/wizardforcel/scapy-docs/details
在命令行输入以下命令
pip install scapy
pip install ipython#该模块可以让交互环境更加友好
注意 windows下安装scapy需要安装winpcap或者是npcap.
Scapy的交互shell是运行在一个终端会话中.
在Linux中,需要root权限才能发送数据包,所以在这里必须使用sudo
$ sudo scapy
Welcome to Scapy(2.4.2-dev)
在Windows中,使用管理员权限打开命令提示符(cmd.exe):
输入scapy可以看到如下结果.
有警告信息是因为没有安装所有的可选包,Scapy会告诉有哪些功能不可用.
注:可以在交互环境下输入 show_interfaces() 来查看本机的网卡名称
使用sniff函数进行嗅探流量,
>>> pkts = sniff(count = 10)
>>> pkts
这条命令是使用默认的网卡嗅探10 个包,结果得到八个TCP一个UDP包,以及一个其他类型包.
使用pkts[i]来查看具体的包的内容.
其中Ether为网络接口层数据,dst,src为目标MAC地址和源MAC地址.
IP为网络层的数据,可以得到使用的协议,源IP地址目标IP地址,TTL的值等.
UDP为运输层数据,可以得到源端口目的端口等信息.
Raw为应用层信息,其中含有要发送的数据
.show()可以更加详细的看到数据
summary()可以看到大概的有标识信息的信息.
>>> pkts[1].summary()
'Ether / IP / TCP 10.245.3.203:52021 > 222.22.29.94:https PA / Raw'
各参数的含义:
iface表示使用的网卡接口,如果没有指定则会在所有的interface上进行嗅探(在交互环境输入show_interfaces()可以查看所有的网卡)
count是嗅探包的个数
filter是过滤条件
prn是回调函数,通常与lambda搭配使用
sprintf()函数控制输入信息
演示:
>>> a = sniff(filter = 'tcp and (port 25 or port 110)',prn = lambda x: x.sprintf('%IP.src%:%TCP.sport% -> %IP.dst%:%TCP.dport% %2s,TCP.flags% : %TCP.payload%))
这条语句的含义是,筛选协议为tcp并且端口为25或者是110的的packet,并且按照给定的格式输出.
使用wrpacp和rdpcap可以将嗅探到的packet内容写入到pcap文件和读取pacp文件中.其他抓包软件也可以打开.
#写入
wrpacp('demo.pacp',pkts)
#读取
read_pkts = rdpacp('demo.pcap')
read_pkts
>>>
Scapy允许以不同的十六进制格式输出编码的数据包
使用**hexdump()**函数可以以经典的hexdump格式(十六进制)输出数据包.
使用import_hexcap()函数可以将hexdump格式重新导入到Scapy中
使用str()函数可以将整个数据包转换成十六进制字符串.
>>> pkts = sniff(count = 3)
>>> pkt = pkts[0]
>>> pkt
>>>
>>> str(pkt)
'b"\\xff\\xff\\xff\\xff\\xff\\xff\\x9c\\xb6\\xd0\\x07\\xdf\\x83\\x08\\x00E\\x00\\x01#_\\x0f\\x00\\x00@\\x11\\xf3\\x1f\\ne\\x02\\xd3\\ne\\x0f\\xff\\xd6\\x83\\xd6\\x83\\x01\\x0f\\xb7\\x02\\x00USER-QO5VP7A5TA\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x000o\\r\\x02\\x00\\x00\\x00\\x00\\x90\\xbb\\xfc\\x06\\x00\\x00\\x00\\x003\'\\x00\\x00\\x00\\x00\\x00\\x00 o\\r\\x02\\x00\\x00\\x00\\x00\\xd0xK\\x05\\x00\\x00\\x00\\x00|j\'n\\x00\\x00\\x00\\x00\\xc8\\xa5\\xdan\\x00\\x00\\x00\\x00\\xb9\\xbf\\xfc\\x06\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x80^\\x0f\\x05\\x00\\x00\\x00\\x00\\x04\\xbc\\xfc\\x06\\x00\\x00\\x00\\x00 \\xbc\\xfc\\x06\\x00\\x00\\x00\\x00\\x08/\\x80{627f3fa9-86ea-4076-bd57-9deaef085603}\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xbc\\xfc\\x06\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xf0\\x90\\xcdF"'
export_object() 函数:
Scapy可以将数据包转换为base64编码的Python数据结构
>>> pkt
>>>
>>> export_object(pkt)
b'eNprYEouTk4sqNTLSaxMLSrWyzHici3JSC3iKmTQDCpkTI5Pzk9JTS7mSs0DMbgKmSIiGRkYDu9HwENzDm07PIH98PxDzRwMrgyMyvH8DAwOgoc3y3OlMh2ezJXKD1Q17VAzCDPyH9rOxBAa7BqkG+hvGhZg7mga4siABgzyeZlA9KEJh3Yf3sMGYhqrQ6QUoFKHJ1R4s4IYNVnqeWCBjkNLD88CMw/tPLQfqg0GDjXE8YOVsxzaA5VSgLM49A81VJsZmacZpyVa6lqYpSbqmhiYm+kmpZia61qmpCamphlYmJoZGNdCTWOEG7sHzR4KwOENhyYc7nUrZI4AmZiTWJKZZ1jI0lbIGlTI1lrInqQHAGGUZtg='
可以使用save_session()函数保存所有的session变量
>>> dir()
['__builtins__', 'conf', 'new_pkt', 'pkt', 'pkt_export', 'pkt_he x', 'pkt_str', 'pkts']
>>> save_session("session.scapy")
使用load_session()函数,在下一次启动Scapy的时候就能加载保存的session
>>> dir()
['__builtins__', 'conf']
>>> load_session("session.scapy")
>>> dir()
['__builtins__', 'conf', 'new_pkt', 'pkt', 'pkt_export', 'pkt_he x', 'pkt_str', 'pkts']
第一步,建立一个简单的数据包
>>> a = IP(ttl = 10)
>>> a
>>> a.src
'10.245.3.203'
>>> a.dst = '119.75.217.26'
>>> a
>>> del(a.ttl)
>>> a
>>> a.ttl
64
’ / ’ 操作符在两层之间起到一个组合的作用.当使用该操作符的时候,下层可以根据其上层,使它的一个或多个默认字段被重载,但还是可以赋予你想要的值.
>>> IP()
>>> IP()/TCP()
>
>>> Ether()/IP()/TCP()
>>
>>> IP()/TCP()/'GET /HTTP/1.0\r\n\r\n'
>>
>>> IP(proto=55)/TCP()
>
每一个数据包都可以被建立或者是分解
>>> a = Ether()/IP(dst='www.baidu.com')/TCP()/'GET /index.html HTTP/1.0 \n\n'
>>> hexdump(a)
0000 7C 1E 06 24 40 DB A4 02 B9 B4 D4 3A 08 00 45 00 |..$@......:..E.
0010 00 43 00 01 00 00 40 06 20 1A 0A F5 03 CB DC B5 .C....@. .......
0020 6F 25 00 14 00 50 00 00 00 00 00 00 00 00 50 02 o%...P........P.
0030 20 00 63 17 00 00 47 45 54 20 2F 69 6E 64 65 78 .c...GET /index
0040 2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A .html HTTP/1.0 .
0050 0A
>>> b = str(a)
>>> b
"b'|\\x1e\\x06$@\\xdb\\xa4\\x02\\xb9\\xb4\\xd4:\\x08\\x00E\\x00\\x00C\\x00\\x01\\x00\\x00@\\x06 \\x1a\\n\\xf5\\x03\\xcb\\xdc\\xb5o%\\x00\\x14\\x00P\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\x02 \\x00c\\x17\\x00\\x00GET /index.html HTTP/1.0 \\n\\n'"
>>> d = IP(a)
>>> d
, , , ] |>
以下是一些常用的命令
命令 | 效果 |
---|---|
str(pkt) | 组装数据包 |
hexdump(pkt) | 十六进制转储 |
Is(pkt) | 显示出字段值的列表 |
pkt.summary() | 一行摘要 |
pkt.show() | 针对数据包的展开 |
pkt.show2() | 显示聚合的数据包 |
pkt.decode_payload_as() | 改变decode方式 |
pkt.psdump() | 绘制一个解释说明的PostScript图表 |
pkt.pdfdump() | 绘制一个解释说明的PDF |
pkt.command() | 返回可以生成数据包的Scapy的命令 |
轻易的定制一组数据包:整个数据包的每一个字段都可以是一组,可以使用所有区域之间的笛卡尔积来生成一组数据包.
>>> a = IP(dst = '10.245.3.203/30')
>>> [p for p in a]
[,
,
,
]
>>> b = IP(ttl=[1,2,(5,9)])
>>> b
>>> [p for p in b]
[,
,
,
,
,
,
]
>>> c=TCP(dport=[80,443])
>>> [p for p in a/c]
[>,
>,
>,
>,
>,
>,
>,
>]
send() 函数将会在第3层发送数据包,会处理路由和第二层的数据.
sendp() 函数将会工作在第2层,可以自主的选择合适的接口和正确的链路协议.
send()和sendp()只是发送,并没有接受
sr() 函数是用来发送数据包和接受应答.该函数返回一对数据包及其应答,还有无应答的数据包
sr1() 函数是一种变体,用来返回一个应答数据包,发送的数据包必须是第3层报文(IP,ARP等)
srp() 则是使用第2层报文(以太网,802.3等)
以下例子是通过发送arp请求包来查看某一个IP或者是网段的存活情况,但是必须是与主机IP在同一个局域网内.
from scapy.all import srp, Ether, ARP
IpScan = input('请输入IP:')
print("扫描中,请稍候...")
ans,unans = srp(Ether(dst="FF:FF:FF:FF:FF:FF")/ARP(pdst=IpScan),timeout=2,verbose=0,iface="Intel(R) Dual Band Wireless-AC 7265")
#verbose 不说明下载的形况
print("本次扫描一共扫描到%d台主机:" % len(ans))
for send,recv in ans:
print("%s----%s"%(recv.src,recv.psrc))
使用
from scapy.all import *
在import后加入所需要的功能即可
例子: 传入一个IP或者是一个主机名作为参数,发送一个ICMP响应请求,然后显示返回包完整的构造.
import sys
from scapy.all import sr1,IP,ICMP
p=sr1(IP(dst=sys.argv[1])/ICMP())
if p:
p.show()
注: sys模块中的sys.argv[1]用法可以在命令行中得到你想传入的参数
如:
scapy.py 127.0.0.1
sys.argv[1]就等于 127.0.0.1