数据包处理利器——Scapy基础知识

简介: 数据包处理利器——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支持的协议


640.png


使用lsc()查看scapy支持的函数


640.png


还可以使用ls()获取协议包含的参数


640.png


发送和接收数据包


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.
...**...............................^C
Received 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 0
RECV 1: IP / ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0
RECV 1: IP / ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0
RECV 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 pkt
True


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()函数可帮助我们捕获所有流量:


  • 包括countfilterifacelfilterprntimeout选项。


>>> 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 S
Ether / IP / TCP 60.205.177.168:54624 > 172.17.51.80:http S
Ether / IP / TCP 172.17.51.80:http > 60.205.177.168:54624 SA
Ether / IP / TCP 60.205.177.168:http > 172.17.51.80:54624 SA
Ether / 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 S
0001 Ether / IP / TCP 74.125.95.104:http > 172.16.16.128:1606 SA
0002 Ether / IP / TCP 172.16.16.128:1606 > 74.125.95.104:http A
0003 Ether / IP / TCP 172.16.16.128:1606 > 74.125.95.104:http PA / Raw
0004 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>


相关文章
|
JSON 网络协议 Unix
iPerf3 命令通用选项
iPerf3 命令通用选项
|
Kubernetes 搜索推荐 开发者
探索后端开发的未来之路:微服务架构与容器化技术
随着云计算技术的不断成熟和普及,后端开发领域正经历着前所未有的变革。本文将深入探讨微服务架构和容器化技术如何重塑后端开发的面貌,提升系统的可扩展性、灵活性和可靠性。通过分析现代后端系统面临的挑战,我们将展示微服务和容器化如何提供解决方案,并预测这些技术如何塑造后端开发的未来发展。
392 29
《stm32嵌入式系统开发实战指南》一3.3 创建工程
本节书摘来自华章出版社《stm32嵌入式系统开发实战指南》一书中的第3章,第3.3节,作者 李志明 檀永 徐石明,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1764 0
|
消息中间件 Kubernetes Cloud Native
iLogtail 开源两周年:感恩遇见,畅想未来
凡是过往,皆为序章;iLogtail 社区,是我们共同编织的果实。所有将来,皆为可盼;LoongCollector,是我们共筑的未来。
946 169
|
存储 Python
海龟编程 python绘图工具turtle库的用法 turtle库使用方法大全,画笔设置 画布设置 绘图设置,画笔粗细,画笔颜色, 画笔速度。
海龟编程 Python绘图工具trutle库的使用方法 trutle库命令大全,总结了常用命令,学会这些命令,玩转turtle库
1938 0
|
机器学习/深度学习 并行计算 PyTorch
【多GPU炼丹-绝对有用】PyTorch多GPU并行训练:深度解析与实战代码指南
本文介绍了PyTorch中利用多GPU进行深度学习的三种策略:数据并行、模型并行和两者结合。通过`DataParallel`实现数据拆分、模型不拆分,将数据批次在不同GPU上处理;数据不拆分、模型拆分则将模型组件分配到不同GPU,适用于复杂模型;数据和模型都拆分,适合大型模型,使用`DistributedDataParallel`结合`torch.distributed`进行分布式训练。代码示例展示了如何在实践中应用这些策略。
3715 2
【多GPU炼丹-绝对有用】PyTorch多GPU并行训练:深度解析与实战代码指南
|
移动开发 前端开发 Java
ruoyi-nbcio-plus后端里mapstruct-plus和lombok的使用
ruoyi-nbcio-plus后端里mapstruct-plus和lombok的使用
676 0
|
移动开发 小程序 安全
DingTalk「开发者说」— 钉钉数据授权开发实战
随着《中华人民共和国网络安全法》的实施,对个人信息的保护越来越严格,钉钉遵守安全法要求,对钉钉上个人信息的收集、使用、共享有严格的把关。本次分享主要介绍钉钉如何做个人数据把关,以及在个人选择同意原则下,如何对个人数据做授权流转,以及实践演练。 DingTalk「开发者说」是钉钉开发者最新上线的开发者栏目,联合阿里云ACE团队,分享钉应用开发解决方案、技术更新、实战技巧,致力于成为钉钉与开发者的桥梁与纽带,让更多的钉钉开发者传播技术、提升技能、分享观点。在数字化变革的时代,“云钉一体”“钉钉全面开放”战略之后,希望钉钉技术可以持续激发开发者的创造力,为组织数字化赋能。
3094 4
DingTalk「开发者说」— 钉钉数据授权开发实战
|
存储 缓存 数据管理
ceph存储 一文看懂目录配额(从入门到进阶,内涵完整流程和源码分析)
在Ceph文件系统(CephFS)中,目录配额是一项功能,它允许管理员限制特定目录下可以使用的存储空间总量和/或文件数量。这项功能对于控制资源消耗和防止个别用户或应用程序过度占用共享存储资源特别有用。
1462 1
|
Web App开发 安全 索引
网站点击进去出现“该内容被禁止访问”的拦截处理
很多客户的网站被拦截并提示:“该内容被禁止访问”,大多数客户使用的都是阿里云的虚拟主机以及ECS服务器,最近发生这种问题的网站也越来越多,这几天刚解决完一个客户网站被阿里云:违规URL屏蔽访问处理通知并拦截,经过朋友介绍找到我们SINE安全公司。

热门文章

最新文章