51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 697|回复: 0
打印 上一主题 下一主题

[python] 分享Python之pypcap库的安装及简单抓包工具的实现

[复制链接]
  • TA的每日心情
    无聊
    3 天前
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2023-3-24 11:39:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    pypcap是一个对libpcapC库进行封装和简化的面向对象的抓包工具库,可以非常方便的用于抓包和过滤,结合dpkt解析库可以完成许多网络数据包的抓取和分析。本文讲述的就是如何使用pypcap及dpkt库实现简单抓包工具,也称为嗅探器(sniffer).
      Linux 端安装 pypcap
      sudo apt-get install libpcap-dev
      sudo pip install pypcap


      这里有个问题,如果使用Anaconda目录的pip安装则可能失败,目前原因未明,但官方的python3对应的pip3及python2对应的pip均无此问题。
      Windows 端安装 pypcap
      根据pypcap官方说明:
      WinPcap has compatibility issues with Windows 10, therefore it's recommended to use Npcap (Nmap's packet sniffing library for Windows, based on the WinPcap/Libpcap libraries, but with improved speed, portability, security, and efficiency). Please enable WinPcap API-compatible mode during the library installation.

      这里提到winpcap与win10间存在兼容性问题,具体什么问题我也没搞清楚,之前使用wireshark抓包一直用的winpcap也没问题。不过我估计和后面要用到的npcap sdk有关吧。既如此,就需要在安装pypcap前安装好Npcap,并下载好Npcap SDK。
      下载文件
      ·pypcap 源码
      · Npcap
      · Npcap SDK
      安装
      · 安装Npcap
      安装下载后的Npcap安装包,如果电脑带有无线网卡,记得勾选“support raw 802.11 traffic(and monitor mode) for wireless adapters”。需要注意的是,如果电脑已经安装过winpcap软件,在安装Npcap时会弹窗提示卸载Winpcap,此时需要关闭wireshark或是其它相关的软件
      · 安装pypcap
      1. 将Npcap SDK文件夹和pypcap源码文件夹放在一个目录下;
      2. 将Npcap SDK文件夹名称修改为wpdpack;
      3. 进入pypcap源码目录,执行python setup.py install即可完成安装。
      在第三步需要注意的是,如果Python版本为3.7.2(其它大于3.7的版本没试过)有可能编译失败,因为有个头文件pystate.h在高版本会有更新,导致结构体_ts PyThreadState中的某些参数不识别,从而提示错误pcap.c(22849): error C2039: 'exc_value': is not a member of '_ts'等。之后我将版本换至3.6.6后便正常编译了。
      安装完成后,可以进入python执行import pcap查看是否已经可以正常导入。
      简单使用
      import pcap
      # list all of the Internet devices
      devs = pcap.findalldevs()
      print(*devs, sep='\n')
      pc = pcap.pcap(devs[3], promisc=True, immediate=True, timeout_ms=50)
      # fiter http pcakets
      pc.setfilter('tcp port 80')
      for ptime, pdata in pc:
          print(ptime, pdata)


      接下来简单解释下几个主要函数:
      findalldevs
      findalldevs可以列出当前操作系统的所有网络接口,但是windows和Linux的输出风格不大一样,下面来看看。
      Linux版输出简单明了,若我猜的不错,输出的首个接口便是电脑的有线接口(本人台式机,Ubuntu系统),至少在我这是适用的。
      python
      Python 3.6.7 (default, Oct 22 2018, 11:32:17)
      [GCC 8.2.0] on linux
      Type "help", "copyright", "credits" or "license" for more information.
      >>> import pcap
      >>> pcap.findalldevs()
      ['enp2s0', 'any', 'lo', 'nflog', 'nfqueue', 'usbmon1', 'usbmon2']
      >>>


      在ubuntu及大部分Linux系统中,均可使用ip route或是ifconfig来获取接口名,据此甚至可以自动获取接口名。
      Windows版则比较复杂,下面是某台电脑win10操作系统输出的结果,这个直接看是看不出什么的, 因为使用cmd指令ipconfig /all输出的接口信息并不包含以下内容,而是接口名称及描述信息等,如果想知道下面接口如何与接口名对应起来,可以参考后面抓包工具使用注册表来获取接口信息,或是打开wireshark抓包,每个报文的帧头都会显示当前接口的接口信息。
      >>> import pcap
      >>> pcap.findalldevs()
      ['\Device\NPF_{839768E4-726A-48BB-9CEC-BD6FD670CB8F}', '\Device\NPF_{C4D1AF17-C5C9-40C5-90F8-17781657FC9E}', '\Device\NPF_{26024876-9711-428F-89D3-B91D2C488AC5}', '\Device\NPF_{E26BFFEF-0644-4C13-8016-EB408AE1D471}', '\Device\NPF_{9ED3674C-211E-4A57-923A-F8DBE6E6B704}', '\Device\NPF_{A0B8B562-F309-44F3-95A1-BF34F5465925}', '\Device\NPF_{9D76B006-6946-4C88-AED2-7F7A9194303C}']


      pcap.pcap
      pc = pcap.pcap(devs[3], promisc=True, immediate=True, timeout_ms=50)

      以上代码定义了一个pcap对象,首个参数devs[3]对应接口名,promisc为真代表打开混杂模式,immediate代表立即模式,启用将不缓存数据包,timeout_ms代表接收数据包的超时时间。
      setfilter
      setfilter用来设置数据包过滤器,比如只想抓http的包,那就通过setfilter(tcp port 80)实现,更加详细的过滤规则请自行谷歌
      抓包
      for ptime, pdata in pc:
          print(ptime, pdata)


      pcap.pcap对象pc是个动态数据,通常结合for循环或是while循环不断读取数据包,数据包会返回时间戳及报文数据。
      上面这个小例子就是简单的说明pcap常用库函数的使用方法.具体的数据包的存储及解析需要由解析库dpkt来完成.下面是一个更加详细的抓包工具实例,可以完成数据包的抓取、解析及存储。
      简易抓包工具
      #!/usr/bin/env python3
      # -*- encoding:utf-8 -*-
      import pcap
      import dpkt
      import getopt
      import sys
      import datetime
      import time
      import os
      import platform
      if 'Windows' in platform.platform():
          import winreg as wr
      IF_REG = r'SYSTEM\CurrentControlSet\Control\Network\{4d36e972-e325-11ce-bfc1-08002be10318}'
      def getInterfaceByName(name):
          '''Get guid of interface from regedit of windows system
          Args:
              name: interface name
          Returns:
              An valid guid value or None.
          Example:
              getInterfaceByName('eth0')
          '''
          reg = wr.ConnectRegistry(None, wr.HKEY_LOCAL_MACHINE)
          reg_key = wr.OpenKey(reg, IF_REG)
          for i in range(wr.QueryInfoKey(reg_key)[0]):
              subkey_name = wr.EnumKey(reg_key, i)
              try:
                  reg_subkey = wr.OpenKey(reg_key, subkey_name + r'\Connection')
                  Name = wr.QueryValueEx(reg_subkey, 'Name')[0]
                  wr.CloseKey(reg_subkey)
                  if Name == name:
                      return r'\Device\NPF_' + subkey_name
              except FileNotFoundError as e:
                  pass
          return None
      def mac_addr(mac):
          return '%02x:%02x:%02x:%02x:%02x:%02x'%tuple(mac)
      def ip_addr(ip):
          return '%d.%d.%d.%d'%tuple(ip)
      def captureData(iface):
          pkt = pcap.pcap(iface, promisc=True, immediate=True, timeout_ms=50)
          # filter method
          filters = {
              'DNS': 'udp port 53',
              'HTTP': 'tcp port 80'
          }
          # pkt.setfilter(filters['HTTP'])
          pcap_filepath = 'pkts/pkts_{}.pcap'.format(time.strftime("%Y%m%d-%H%M%S",
              time.localtime()))
          pcap_file = open(pcap_filepath, 'wb')
          writer = dpkt.pcap.Writer(pcap_file)
          print('Start capture...')
          try:
              pkts_count = 0
              for ptime, pdata in pkt:
                  writer.writepkt(pdata, ptime)
                  # anlysisData(pdata)
                  printRawPkt(ptime, pdata)
                  pkts_count += 1
          except KeyboardInterrupt as e:
              writer.close()
              pcap_file.close()
              if not pkts_count:
                  os.remove(pcap_filepath)
              print('%d packets received'%(pkts_count))
      def printRawPkt(time, data):
          eth = dpkt.ethernet.Ethernet(data)
          print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(time)))
          print('Ethernet Frame: ', mac_addr(eth.src), mac_addr(eth.dst))
          if not isinstance(eth.data, dpkt.ip.IP):
              print('')
              return
          ip = eth.data
          # get fragments info
          do_not_fragment = bool(ip.off & dpkt.ip.IP_DF)
          more_fragments = bool(ip.off & dpkt.ip.IP_MF)
          fragment_offset = ip.off & dpkt.ip.IP_OFFMASK
          print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)\n' % (
              ip_addr(ip.src), ip_addr(ip.dst), ip.len, ip.ttl,
              do_not_fragment, more_fragments, fragment_offset))
      def anlysisData(data):
          packet = dpkt.ethernet.Ethernet(data)
          if isinstance(packet.data, dpkt.ip.IP):
              ip = ip_addr(packet.data.dst)
              if packet.data.data.dport == 80 or packet.data.data.sport == 80:
                  try:
                      print(packet.data.data.data.decode('utf-8', errors='ignore'))
                  except UnicodeDecodeError as uderr:
                      print(uderr.__str__())
      def main():
          if 'Windows' in platform.platform():
              iface = getInterfaceByName('Router')
          else:
              iface = 'enp2s0'
          captureData(iface)
      if __name__ == "__main__":
          main()


      简要说明
      ·获取接口
      getInterfaceByName根据接口名称,通过查找注册表信息获取pcap所需的接口设备信息,适用于Windows系统.至于Linux系统,直接通过ifconfig获取即可,至于自动获取功能,目前还没写,以后再说吧。
      · 数据包存储
      为了将数据包存储到.pcap文件(此类文件可以使用wireshark打开)中,可以通过dpkt.pcap.Writer对象使用writepkt函数不断写入文件。
      pcap_file = open(pcap_filepath, 'wb')
      writer = dpkt.pcap.Writer(pcap_file)
      for ptime, pdata in pkt:
          writer.writepkt(pdata, ptime)


      · 打印数据包基本信息
      printRawPkt是个非常简单的打印数据包基本信息的函数,最多仅打印至ip信息,打印格式如下:
      Timestamp:  2018-12-31 13:58:39.850904
      Ethernet Frame:  00:e0:4c:5a:0a:78 00:0f:e9:61:30:00
      IP: 192.168.1.76 -> 59.111.160.197 (len=52 ttl=64 DF=1 MF=0 offset=0)


      信息包含时间戳,以太网帧的MAC地址,IP地址及分片信息等。
      · 解析http数据包
      anlysisData函数目前只是简单的检测及打印解码后的http包,使用dpkt.ethernet.Ethernet可以将原始数据包封装成一个结构化的以太网帧,之后按照网络协议栈的顺序便可逐层解析出链路层、网络层、传输层直至应用层.以上代码先是判断是否为IP报文,之后根据端口号判断是否为http报文,然后将数据解码后输出.
      这个例子也很简单,很多异常情况也没考虑,本文主要目的是描述pypcap和dpkt的常用方法以及抓包工具的实现过程,至于针对具体协议的解析则需继续学习.
      抓包[url=]测试[/url]
      mkdir pkts
      sudo ./pktcap.py
      Start capture...
      Timestamp:  2018-12-31 13:58:37.148964
      Ethernet Frame:  00:36:76:6c:28:fe 33:33:00:00:00:16
      Timestamp:  2018-12-31 13:58:37.148978
      Ethernet Frame:  00:36:76:6c:28:fe 33:33:00:00:00:16
      Timestamp:  2018-12-31 13:58:37.529024
      Ethernet Frame:  00:36:76:6c:28:fe 33:33:00:00:00:16
      Timestamp:  2018-12-31 13:58:37.809011
      Ethernet Frame:  98:e0:d9:a4:50:1d 33:33:00:00:00:16
      Timestamp:  2018-12-31 13:58:39.850904
      Ethernet Frame:  00:e0:4c:5a:0a:78 00:0f:e9:61:30:00
      IP: 192.168.1.76 -> 59.111.160.197 (len=52 ttl=64 DF=1 MF=0 offset=0)
      Timestamp:  2018-12-31 13:58:39.862890
      Ethernet Frame:  00:0f:e9:61:30:00 00:e0:4c:5a:0a:78
      IP: 59.111.160.197 -> 192.168.1.76 (len=40 ttl=55 DF=1 MF=0 offset=0)
      Timestamp:  2018-12-31 13:58:40.289465
      Ethernet Frame:  b0:19:c6:17:0a:57 33:33:00:00:00:16
      Timestamp:  2018-12-31 13:58:40.369068
      Ethernet Frame:  a4:d1:8c:0b:54:12 33:33:00:00:00:16
      Timestamp:  2018-12-31 13:58:41.859034
      Ethernet Frame:  a0:4e:a7:e0:65:3d 33:33:00:00:00:16
      Timestamp:  2018-12-31 13:58:42.079218
      Ethernet Frame:  8c:6d:50:7d:f9:fc ff:ff:ff:ff:ff:ff
      IP: 0.0.0.0 -> 255.255.255.255 (len=352 ttl=64 DF=0 MF=0 offset=0)
      ^C10 packets received
      cd pkts
      ls
      pkts_20181230-185017.pcap  pkts_20181231-203416.pcap  pkts_20181231-215837.pcap



    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-24 19:04 , Processed in 0.072556 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表