数据包处理利器——Scapy基础知识
欢迎关注个人公号:运维开发故事
什么 是scapy
Scapy是功能强大的交互式数据包处理程序。它能够伪造或解码各种协议的数据包,在线发送,捕获,匹配请求和响应等。它可以轻松处理大多数经典任务,例如扫描,跟踪路由,探测,单元测试,***或网络发现,它可以代替hping,arpspoof,arp-sk,arping,p0f甚至Nmap,tcpdump和tshark的某些部分。。它在其他工具无法处理的许多其他特定任务上也表现出色,例如发送无效帧,组合技术(VLAN跳变+ ARP缓存中毒,WEP加密通道上的VOIP解码等等)
安装scapy
直接pip安装即可,我使用的是python3
pip3 install scapy
scapy基本使用
输入scapy回车进入scapy的shell
可以使用ls()来查看scapy支持的协议
使用lsc()查看scapy支持的函数
还可以使用ls()获取协议包含的参数
发送和接收数据包
send
- 在第3层发送数据包(Scapy创建第2层标头),不接收任何数据包。
loop
参数默认为0,如果它的值不是0,那么数据包将一直循环发送,直到按CTRL-C为止。count
可用于设置要发送的数据包的确切数量。inter
可用于设置每个数据包之间的秒数。>>> send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S')).Sent 1 packets.>>> >>> send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'), count=10)..........Sent 10 packets.>>>>>> send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'), loop=1)......................... [... snipped ...]Sent 1503 packets.
sendp
- 与send()相同,但在第2层发送数据包(必须提供第2层标头),不接收任何数据包。
- 使用
iface
到设置界面上发送数据包。(如果未设置,将使用conf.iface
的值)>>> sendp(Ether()/IP(dst="1.2.3.4",ttl=(1,4)), iface="eth0")....Sent 4 packets.
sendp("I’m travelling on Ethernet", iface="eth0", loop=1, inter=0.2)
sendp(rdpcap("/tmp/pcapfile")) # tcpreplay
...........
Sent 11 packets.#### sr
- 发送数据包并接收响应。
sr()返回两个列表,第一个列表包含响应的,第二个列表包含未响应的。
>>> sr(IP(dst="60.205.177.168")/TCP(dport=[21,22,23]))Begin emission:Finished sending 3 packets....**...............................^CReceived 36 packets, got 2 answers, remaining 1 packets(<Results: TCP:2 UDP:0 ICMP:0 Other:0>,<Unanswered: TCP:1 UDP:0 ICMP:0 Other:0>)>>> ans,unans=_>>> unans.summary()IP / TCP 172.17.51.80:ftp_data > 60.205.177.168:telnet S>>> ans[0](<IP frag=0 proto=tcp dst=60.205.177.168 |<TCP dport=ftp |>>,<IP version=4 ihl=5 tos=0x0 len=40 id=53978 flags=DF frag=0 ttl=64 proto=tcp chksum=0x9a1e src=60.205.177.168 dst=172.17.51.80 |<TCP sport=ftp dport=ftp_data seq=0 ack=1 dataofs=5 reserved=0 flags=RA window=0 chksum=0xe1cf urgptr=0 |>>)>>> ans[0][0]<IP frag=0 proto=tcp dst=60.205.177.168 |<TCP dport=ftp |>>
sr1
发送所有数据包并仅记录第一个响应。
>>> p=sr1(IP(dst="www.baidu.com")/ICMP()/"asdqwe")Begin emission:Finished sending 1 packets..*Received 2 packets, got 1 answers, remaining 0 packets
srloop
- 循环发送,接收响应并显示响应。
该函数返回几个数据包和响应,以及未响应的。
>>> packet = IP(dst='60.205.177.168')/ICMP()>>> srloop(packet)RECV 1: IP / ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0RECV 1: IP / ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0RECV 1: IP / ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0RECV 1: IP / ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0^C Sent 4 packets, received 4 packets. 100.0% hits.(<Results: TCP:0 UDP:0 ICMP:9 Other:0>,<PacketList: TCP:0 UDP:0 ICMP:0 Other:0>)
使用Scapy创建数据包
- Scapy数据包的创建与网络中的分层方法一致。
- 数据包的基本构建块是一层,而整个数据包则是通过将各个层堆叠在一起而构建的。
- scapy通过在TCP / IP的不同层上为每个协议定义数据包头,然后按顺序堆叠这些层,来构造数据包。
在一行中创建数据包
>>> packet = Ether()/IP(dst='8.8.8.8')/TCP(dport=53,flags='S')
分别创建每个图层并使用'/'运算符将它们堆叠
>>> l2 = Ether()>>> l3 = IP(dst='8.8.8.8/30')>>> l4 = TCP(dport=53, flags = 'S')>>> packet = l2/l3/l4
Scapy IP表示法
Scapy接受普通的IP表示法,CIDR表示法,主机名。
>>> packet = IP(dst = '8.8.8.8')>>> packet = IP(dst = 'scanme.nmap.org')>>> packet = IP(dst = '8.8.8.8/30')>>> [a for a in packet][<IP dst=8.8.8.8 |>, <IP dst=8.8.8.9 |>, <IP dst=8.8.8.10 |>, <IP dst=8.8.8.11 |>]>>> packet = IP(dst = 'egadz.metasploit.com/30')
创建一组数据包
我们可以使用Scapy创建一组数据包
>>> pkts = IP(ttl=[1,3,5,(7,10)])/TCP()>>> [pkt for pkt in pkts][<IP frag=0 ttl=1 proto=tcp |<TCP |>>, <IP frag=0 ttl=3 proto=tcp |<TCP |>>, <IP frag=0 ttl=5 proto=tcp |<TCP |>>, <IP frag=0 ttl=7 proto=tcp |<TCP |>>, <IP frag=0 ttl=8 proto=tcp |<TCP |>>, <IP frag=0 ttl=9 proto=tcp |<TCP |>>, <IP frag=0 ttl=10 proto=tcp |<TCP |>>] >>> packet=IP(dst="192.168.*.1-10")/TCP(dport=(0,100)) >>> [a for a in packet][<IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=0 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=tcpmux |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=compressnet |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=3 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=4 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=rje |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=6 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=echo |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=8 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=discard |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=10 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=systat |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=12 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=daytime |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=14 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=netstat |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=16 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=qotd |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=msp |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=chargen |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=ftp_data |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=ftp |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=ssh |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=telnet |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=lmtp |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=smtp |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=26 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=nsw_fe |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=28 |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=msg_icp |>>, <IP frag=0 proto=tcp dst=192.168.1.1 |<TCP dport=30 |>>,
检查数据包
获取数据包的详细说明以及数据类型
>>> packet = IP()/TCP()>>> ls(packet)version : BitField = 4 (4)ihl : BitField = None (None)tos : XByteField = 0 (0)len : ShortField = None (None)id : ShortField = 1 (1)flags : FlagsField = 0 (0)frag : BitField = 0 (0)ttl : ByteField = 64 (64)proto : ByteEnumField = 6 (0)chksum : XShortField = None (None)src : Emph = '127.0.0.1' (None)dst : Emph = '127.0.0.1' ('127.0.0.1')options : PacketListField = [] ([])[-- snipped --]
show
显示详细的包头
>>> packet.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= []
show2
与show()类似,但可以组装数据包并计算校验和和IHL(报头长度,最小值是5)。
>>> packet.show2()###[ IP ]### version= 4 ihl= 5 tos= 0x0 len= 40 id= 1 flags= frag= 0 ttl= 64 proto= tcp chksum= 0x7ccd src= 127.0.0.1 dst= 127.0.0.1 \options\###[ TCP ]### sport= ftp_data dport= http seq= 0 ack= 0 dataofs= 5 reserved= 0 flags= S window= 8192 chksum= 0x917c urgptr= 0 options= []
summary
显示数据包的简短的摘要
>>> packet.summary()'IP / TCP 127.0.0.1:ftp_data > 127.0.0.1:http S'
与数据包内部的字段进行交互
>>> Ether(dst="d8:55:a3:fe:80:78")/IP(dst="8.8.8.8")<Ether dst=d8:55:a3:fe:80:78 type=IPv4 |<IP dst=8.8.8.8 |>>>>> packet=_>>> packet.dst'd8:55:a3:fe:80:78'>>> packet[IP].dst'8.8.8.8'
检查数据包中是否存在层
haslayer方法
>>> if packet.haslayer(IP):...: print (packet[IP].dst)...: 8.8.8.8
使用in构造
>>> pkt = IP()/TCP()/DNS()>>> DNS in pktTrue
Scapy的sprintf
sprintf()
方法是Scapy的强大功能之一,在编写自定义工具时非常方便。sprintf
用数据包中的值填充格式字符串,就像C语言库中的sprintf一样,不同的是这里用数据包中的字段值填充格式字符串。>>> packet.sprintf("Ethernet source is %Ether.src% and IP proto is %IP.proto%")'Ethernet source is 00:16:3e:0c:d1:ad and IP proto is tcp'>>> a.sprintf("%dst% %IP.dst% vlan=%Dot1Q.vlan%")'00:00:d4:ae:3f:71 192.168.0.1 vlan=42'>>>>>>a.sprintf(" %TCP.flags% | %5s,TCP.flags% | %#05xr,TCP.flags%")' RA | RA | 0x014'
数据包处理程序
我们可以使用lambda函数编写处理TCP数据包的数据包处理程序,但该功能仅适用于TCP数据包。
>>> f=lambda x:x.sprintf("%IP.dst%:%TCP.dport%")>>> f(IP(dst="8.8.8.8")/TCP())'8.8.8.8:http'>>> f(IP(dst="8.8.8.8")/UDP())'8.8.8.8:??'
还可以使用sprintf()中的条件子字符串来实现处理其它层的目的。条件子字符串仅在数据包中存在某个层时才触发,否则将被忽略。还可以
!
用于检查是否缺少图层。
条件子字符串格式: {[!]层:子字符串}>>> f=lambda x: x.sprintf("=> {IP:ip=%IP.dst% {UDP:dport=%UDP.dport%}\...: ... {TCP:%TCP.dport%/%TCP.flags%}{ICMP:type=%r,ICMP.type%}}\...: ... {!IP:not an IP packet}")>>> f(IP()/TCP())'=> ip=127.0.0.1 http/S'>>> f(IP()/UDP())'=> ip=127.0.0.1 dport=domain'>>> f(IP()/ICMP())'=> ip=127.0.0.1 type=8'>>> f(Ether()/ARP())'=> not an IP packet'
导入与导出数据
PCAP格式
从PCAP文件导入数据包。
pkts = rdpcap("temp.cap")pkts = sniff(offline="temp.cap")
将数据包导出到pcap文件。
wrpcap("temp.cap",pkts)
十六进制转储格式
- Scapy允许以各种十六进制格式导出数据包。
使用hexdump()函数使用hexdump格式显示一个或多个数据包:
>>> hexdump(s)0000 D8 55 A3 FE 80 78 00 16 3E 0C D1 AD 08 00 45 00 .U...x..>.....E.0010 00 28 00 01 00 00 40 06 8B 5E AC 11 33 50 08 08 .(....@..^..3P..0020 08 08 00 14 00 50 00 00 00 00 00 00 00 00 50 02 .....P........P.0030 20 00 A0 0D 00 00
十六进制字符串
还可以使用str()函数将整个数据包转换为十六进制字符串
>>> s<Ether dst=d8:55:a3:fe:80:78 type=IPv4 |<IP frag=0 proto=tcp dst=8.8.8.8 |<TCP dport=http |>>>>>> str(s)WARNING: Calling str(pkt) on Python 3 makes no sense!"b'\\xd8U\\xa3\\xfe\\x80x\\x00\\x16>\\x0c\\xd1\\xad\\x08\\x00E\\x00\\x00(\\x00\\x01\\x00\\x00@\\x06\\x8b^\\xac\\x113P\\x08\\x08\\x08\\x08\\x00\\x14\\x00P\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\x02 \\x00\\xa0\\r\\x00\\x00'"
Base64
Scapy可以使用export_object()函数导出数据包的base64编码数据。
>>> export_object(s)b'eNprYEouTk4sqNTLSaxMLSrWyzHici3JSC3iKmTQDCpk1EiOT85PSU0u5krNAzG4Cpki7BkYGA7PCD20+PC+Qw0VDGJ2PIcnHlrLweDKwKDBwMjA4MB2qDvu0BpB4wAOIGAQYQhggIIAJgWGQwt4GRgKmSPYgPycxJLMPMNClrZC1qBCNnfHGxoeDcsdkv2AoKSQPUkPALURLMU='>>> new_pkt = import_object
嗅探
Sniff()
sniff()函数
可帮助我们捕获所有流量:包括count
,filter
,iface
,lfilter
,prn
,timeout
选项。>>> sniff(count=4, iface='eth0')<Sniffed: TCP:1 UDP:3 ICMP:0 Other:0>
可以添加过滤以捕获需要的数据包,使用标准的tcpdump / libpcap语法:
>>> pkts = sniff(count=1,filter="tcp and host 60.205.177.168 and port 80")>>> pkts.summary()Ether / IP / TCP 172.17.51.80:54578 > 60.205.177.168:http S
可以做类似tcpdump的简单流量分析器
>>> pkts = sniff(count=5,filter="host 60.205.177.168",prn=lambda x:x.summary())Ether / IP / TCP 172.17.51.80:54624 > 60.205.177.168:http SEther / IP / TCP 60.205.177.168:54624 > 172.17.51.80:http SEther / IP / TCP 172.17.51.80:http > 60.205.177.168:54624 SAEther / IP / TCP 60.205.177.168:http > 172.17.51.80:54624 SAEther / IP / TCP 172.17.51.80:54624 > 60.205.177.168:http A
- 也可以从pcap文件中嗅探数据包。
pkts = sniff(offline='test.pcap')>>> pkts.nsummary()0000 Ether / IP / TCP 172.16.16.128:1606 > 74.125.95.104:http S0001 Ether / IP / TCP 74.125.95.104:http > 172.16.16.128:1606 SA0002 Ether / IP / TCP 172.16.16.128:1606 > 74.125.95.104:http A0003 Ether / IP / TCP 172.16.16.128:1606 > 74.125.95.104:http PA / Raw0004 Ether / IP / TCP 74.125.95.104:http > 172.16.16.128:1606 A / Padding>>> sniff(offline='test.pcap', lfilter = lambda s: s[TCP].flags == 18, prn = lambda x: x[IP].dst)192.168.1.1<Sniffed: TCP:1 UDP:0 ICMP:0 Other:0>
每一份赞赏源于懂得
赞赏
0人进行了赞赏支持
更多相关文章
- 猎鹰与龙飞船基于Linux,采用C++、Chromium与JS开发
- 210427 PHP 运算符 流程控制 字符串定义 定界符 require/include
- 【每周一库】 simsearch - a simple and lightweight fuzzy
- 模拟实现字符串函数及内存函数
- 20210508 字符串的格式化输出
- PHP:字符串系统函数,ASCII字符集转换,url解析函数,字符串散列处
- php之字符串实战注册页面
- 从入门到入土(三)RocketMQ 怎么保证的消息不丢失?
- 【php基础入门】小白整理PHP常用的字符串函数使用总结分析(推荐)