【Scapy】获取流量包【原创】


0x00 参考

Scapy官方文档

Gitgub地址

Scapy中文文档(第三方)

python之用scapy分层解析pcap报文

使用python中的scapy库抓取并解析pcap包(五元组信息)


0x01 前言

由于云厂商的链路监控做得实在是不咋地,所以我们决定自己实现一套网络链路监控系统。

目的效果:客户端安装agent,实时采集流量数据并且进行上报给服务器端,不管是HTTP、HTTPS、MySQL,以及底层的TCP、UDP,甚至是链路层的,都需要实时采集并上报。

由于我们团队使用Python的居多,所以第一版以Python为开发语言进行开发。一番调研之下,客户端的agent决定使用Scapy来进行流量的获取


0x02 概述

Scapy是一个强大的,用Python编写的交互式数据包处理程序,它能让用户发送、嗅探、解析,以及伪造网络报文,从而用来侦测、扫描和向网络发动攻击。Scapy可以轻松地处理扫描(scanning)、路由跟踪(tracerouting)、探测(probing)、单元测试(unit tests)、攻击(attacks)和发现网络(network discorvery)之类的传统任务。

它可以代替hping,arpspoof,arp-sk,arping,p0f 甚至是部分的Nmap,tcpdump和tshark 的功能。

支持很多协议,比如ARP,BOOTP,Dot1Q,DHCP,DNS,GRE,HSRP,ICMP,IP, NTP,RIP,SNMP,STP,PPPoE,TCP,TFTP,UDP等,可以通过ls()查看支持的协议

简单的说,Scapy主要做两件事:发送报文和接收回应。


0x03 安装

由于Scapy是Python的模块,所以可以使用pip进行安装

pip install scapy

注意:由于Scapy需要root权限才能发送数据包,所以建议使用root用户进行安装

安装完成可以直接在命令行中输入scapy测试是否安装成功:

>scapy
INFO: Can't import matplotlib. Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No libpcap provider available ! pcap won't be used
WARNING: No default IPv4 routes found. Your Windows release may no be supported and you have to enter your routes manually
INFO: No IPv6 support in kernel
INFO: Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption. (Dot11)
INFO: Can't import python-cryptography v1.7+. Disabled IPsec encryption/authentication.
WARNING: IPython not available. Using standard Python shell instead.
AutoCompletion, History are disabled.
WARNING: On Windows, colors are also disabled

                     aSPY//YASa
             apyyyyCY//YCa       |
            sY//YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.4.4
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyPC   | Have fun!
              p///Ac            sC///a   |
              PYCpc           A//A   | To craft a packet, you have to be a
       scccccp///pSP///p          p//Y   | packet, and learn how to swim in
      sY/y  caa           S//P   | the wires and in the waves.
       cayCyayP//Ya              pY/Ya   |        -- Jean-Claude Van Damme
        sY/PsYYCc          aC//Yp    |
         sc  sccaCY//PCypaapyCP//YSs
                  spCPY//YPSps
                       ccaacs

注意:如果没有安装所有的可选包,Scapy会显示有些功能不能用,如:

INFO: Can't import matplotlib. Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No libpcap provider available ! pcap won't be used
WARNING: No default IPv4 routes found. Your Windows release may no be supported and you have to enter your routes manually
INFO: No IPv6 support in kernel
INFO: Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption. (Dot11)
INFO: Can't import python-cryptography v1.7+. Disabled IPsec encryption/authentication.

具体可参考:https://scapy.readthedocs.io/en/latest/installation.html#optional-dependencies

注意:Windows平台需要安装Winpcap才能进行嗅探sniff


0x04 使用

1. ls()

进入scapy后,可用ls()来查看scapy支持的网络协议(由于输出内容太长,只截取部分以供参考)
image-20201107013001082
可以看到耳熟能详的ARP,BOOTP,Dot1Q,DHCP,DNS,GRE,HSRP,ICMP,IP,NTP,RIP,SNMP,STP,PPPoE,TCP,TFTP,UDP等等都支持

注意:这里可以带参考,比如ls(IP)来查看IP包的各种默认参数
image-20201107013402457

2. lsc()

进入scapy后,可以用lsc()来查看scapy的函数集。

比较常用的函数有:

  • arpcachepoison(用于arp毒化攻击,也叫arp欺骗攻击)
  • arping(用于构造一个ARP的who-has包)
  • send (用于发3层报文)
  • sendp(用于发2层报文)
  • sniff(用于网络嗅探,类似Wireshark和tcpdump)
  • sr(发送+接收3层报文)
  • srp(发送+接收2层报文)

比如:(由于输出内容太长,只截取部分以供参考)
image-20201107104930877

3. 嗅探流量

嗅探流量的数据包有两种方式:

  • sniff实时抓包
  • 读取pcap文件

sniff函数如下:

def sniff(count=0, store=1, offline=None, prn=None,filter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None,*args,**kargs)

参数含义:

  • count:抓包的数量,0表示无限制,如无限制会一直抓取
  • store:保存抓取的数据包到内存或者丢弃,1:保存,0:丢弃
  • offline:从 pcap 文件读取数据包,而不进行嗅探,默认为None
  • prn:为每一个数据包定义一个回调函数,例如:prn = lambda x: x.summary(); ( packct.summar()函数返回的是对包的统计性信息 ),则抓取到每个包之后进行显示统计信息
  • filter:过滤规则,bpf过滤器,可参考:BPF语法,比如filter=‘udp’、filter=‘tcp and ( port 80 or port 443)’、filter="( ip and dst 8.8.8.8) "
  • L2socket:使用给定的 L2socket
  • timeout:在给定的时间后停止嗅探,默认为 None,如果为0或不设置则会一直抓取,如果为3则是抓取此时到3秒之间的流量
  • opened_socket:对指定的对象使用 .recv() 进行读取;
  • stop_filter:定义一个函数,决定在抓到指定数据包后停止抓包,如:stop_filter = lambda x: x.haslayer(TCP);
  • iface:指定抓包的接口,一般服务器的默认网卡是eth0,如果没有指定interface,则会在所有的interface上面进行嗅探

注意:如果不设置count和timeout的话,那么sniff会卡在那里一直运行着,sniff后面的代码是不会运行的,一般是会配合prn回调函数,且store建议设置为0,不保存到内存


保存成pcap

wrpcap('xxx.pcap', package)

读取pcap

rdpcap('xxx.pcap')

比如:

>>> from scapy.all import *
>>> packets = sniff(count=1)  # 获取一个流量数据包
>>> wrpcap('test.pcpp', packets)  # 保存成pcap
>>> pcap_packets = rdpcap('test.pcap')  # 读取pcap文件
>>> pcap_packets
<test.pacp: TCP:1 UDP:0 ICMP:0 Other:0>
>>> pcap_packets[0]
<Ether  dst=50:d2:f5:fd:85:e2 src=d4:6d:6d:1c:93:50 type=IPv4 |<IP  version=4 ihl=5 tos=0x0 len=41 id=17191 fla
gs=DF frag=0 ttl=64 proto=tcp chksum=0x574f src=192.168.31.179 dst=14.215.177.38 |<TCP  sport=2894 dport=https
seq=622811909 ack=621991385 dataofs=5 reserved=0 flags=A window=510 chksum=0x8563 urgptr=0 |<Raw  load='\x00' |
>>> pcap_packets[0].src
'd4:6d:6d:1c:93:50'
>>> pcap_packets[0].dst
'50:d2:f5:fd:85:e2'
>>> pcap_packets[0].show()
###[ Ethernet ]### 
  dst       = 50:d2:f5:fd:85:e2
  src       = d4:6d:6d:1c:93:50
  type      = IPv4
###[ IP ]###
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 41
     id        = 17191
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0x574f
     src       = 192.168.31.179
     dst       = 14.215.177.38
     \options   \
###[ TCP ]###
        sport     = 2894
        dport     = https
        seq       = 622811909
        ack       = 621991385
        dataofs   = 5
        reserved  = 0
        flags     = A
        window    = 510
        chksum    = 0x8563
        urgptr    = 0
        options   = []
###[ Raw ]###
           load      = '\x00'

package[0]是查看第一个数据包的数据,package[0].show()是查看第一个数据包的详细信息

scapy是按照按照 TCP/IP 四层参考模型显示详细包信息的,即:链路层 [Ethernet]、网络层[IP]、传输层[TCP/UDP]、应用层[RAW]

通过上述输出结果,我们可以看出每个层的数据包有哪些属性可以取出。

这里P代表的是Ethernet层。P.dst (取出dst属性)、P.src (取出src属性)、P.type (取出type属性)
每一层都有一个 payload 属性,可以不断进入下一层。

p.payload:IP层(可用 p.payload.* 取出IP层的属性)
p.payload.payload:TCP/UDP层(可用 p.payload.payload.* 取出TCP/UDP层的属性)
p.payload.payload.payload:RAW层(可用 p.payload.payload.payload.* 取出RAW层的属性)

上面显示的是TCP的请求,下面的UDP的请求:

###[ Ethernet ]### 
  dst       = 14:43:d0:65:ae:a2
  src       = 88:b8:5d:bd:0d:7f
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 40
     id        = 28350
     flags     = 
     frag      = 0
     ttl       = 128
     proto     = udp
     chksum    = 0x0
     src       = 192.168.1.56
     dst       = 192.144.236.192
     \options   \
###[ UDP ]### 
        sport     = 59297
        dport     = ms_wbt_server
        len       = 20
        chksum    = 0x6f27
###[ Raw ]### 
           load      = '\xae;\xf8\x01\x04\x00\x04\x04\x00\x01\x07\x00'

4. 发送数据包

发送数据包之前需要构建数据包

构建数据包

比如使用IP()就可以创建默认的数据包,也可以使用TCP()创建TCP包、使用UDP()创建UDP包等,具体可以通过ls()查看,使用 ls(IP()) 可以查看IP数据包可以有哪些参数

比如:

>>> ip_package = IP(dst='8.8.8.8')  # 创建目的地址是8.8.8.8的数据包
>>> ip_package.show()  # 查看数据包的信息
###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = ip
  chksum    = None
  src       = 192.168.31.179
  dst       = 8.8.8.8
  \options   \
>>> ip_package.summary()  # 查看数据包的概要信息
'192.168.31.179 > 8.8.8.8 ip'

可以使用 ‘/’ 操作符来给数据包加上一层。比如构造一个TCP数据包,在IP层指明数据包的目的地址。在TCP层可以设定数据包的目的端口等等。UDP数据包同理

比如:

>>> ip_package = IP(dst='8.8.8.8')/TCP(dport=(53)) # 创建目的地址是8.8.8.8的数据包,目的端口为53
>>> ip_package.show()
###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = None
  src       = 192.168.31.179
  dst       = 8.8.8.8
  \options   \
###[ TCP ]###
     sport     = ftp_data
     dport     = (80, 443)
     seq       = 0
     ack       = 0
     dataofs   = None
     reserved  = 0
     flags     = S
     window    = 8192
     chksum    = None
     urgptr    = 0
     options   = []

发送数据包

构造完数据包就可以进行发送,有以下方法:

send(pkt):发送三层数据包,但不会受到返回的结果。
sr(pkt):发送三层数据包,返回两个结果,分别是接收到响应的数据包和未收到响应的数据包。
sr1(pkt):发送三层数据包,仅仅返回接收到响应的数据包。
sendp(pkt):发送二层数据包。
srp(pkt):发送二层数据包,并等待响应。
srp1(pkt):发送第二层数据包,并返回响应的数据包

比如:

>>> ip_package = IP(dst='8.8.8.8')/TCP(dport=(53))
>>> ans, unans = sr(ip_package)
Begin emission:
Finished sending 1 packets.
........*
Received 9 packets, got 1 answers, remaining 0 packets
>>> ans
<Results: TCP:1 UDP:0 ICMP:0 Other:0>
>>> unans
<Unanswered:
  • 6
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值