专栏首页玄魂工作室PYTHON黑帽编程 4.1 SNIFFER(嗅探器)之数据捕获(下)

PYTHON黑帽编程 4.1 SNIFFER(嗅探器)之数据捕获(下)

上一节(4.1 SNIFFER(嗅探器)之数据捕获(上))中, 我们讲解了通过Raw Socket的方式来编写Sniffer的基本方法。 本节我们继续来编写Sniffer,只不过使用现成的库,可以大大 缩短我们的工作时间和编程难度,和上一篇文章对比就知道了。

4.1.6 使用Pypcap编写Sniffer

如果在你的电脑上找不到pcap模块,需要手动进行安装一下。在Kali中使用下面的命令进行安装:

apt-get install libpcap-dev
pip install pypcap

安装过程如图1,图2:

图1

\ 图2

调用pcap模块的pcap方法可以返回一个用来捕获数据包的pcap对象。

\ 图3

如图3,pcap方法接收5个参数:

  • name,监听的网卡名称。
  • snaplen,捕获的每个数据包的最大长度。
  • promisc,是否开启混杂模式
  • timeout_ms,接收数据包的超时时间
  • immediate,立即模式,如果启用则不会缓存数据包

每一个参数都有默认值,如果有多个网卡的话,需要设置第一个参数的值,传入网卡名称。下面 我们定义一个方法,返回一个pcap对象。

import pcap

def getSniffer(ifName=None,filter=''):
    pc = pcap.pcap('eth0',65535,True)
    if(filter != ''):
        pc.setfilter(filter)
    return pc

在上面的代码中,我们创建了一个pcap对象,然后调用了setfilter方法,设置数据包过滤器。 pcap使用的过滤器为符合BPF格式的数据包过滤字符串。

什么是BPF

伯克利包过滤(Berkeley Packet Filter,BPF)语言。让你能够通过比较第2、3、4层协议中各个数据字段值的方法对流量进行过滤。BPF中内置了一些“基元”来指代一些常用的协议字段。可以用“host”、"prot"之类的基元写出非常简洁的BPF过滤规则,也可以检测位于指定偏移量上的字段(甚至可以是一个位)的值。BPF过滤器也可以由详尽的条件链和嵌套的逻辑“与”、“或”操作组成。

BPF基元

现在,构造一个BPF过滤器的最简单的办法就是使用BPF“基元”来指定协议、协议元素或者其他抓包规则。基元通常是由一个id(名称或序号)再加上一个或多个限定符组成的。 \

  • type限定符:规定了id名或id序号指的是哪种类型的数据,可能的type有host、net、prot和protrange
  • dir限定符:规定了流量是从id流进还是流出的(或两种兼有)。可能的dir有src、dst、ser or dst、src and dst、addr1、addr2、addr3和addr4
  • Proto限定符:规定了所匹配的协议。可能的proto有:ether、fddi、tr、wlan、ip、ip6、arp、rarp、decnet、tcp和udp \

最常用的BPF基元要数“host id”,它是用来过滤与某台主机相关的流量的,其中id一栏中应该填上一个地址或主机名。输入“tcp and host 10.10.10.10”这样的过滤规则,将值获取流入/流出得做10.10.10.10的TCP流量,其他的所有帧都会被过滤掉。

举例说明:

假设我们现在希望仅仅获取IP地址为192.168.0.1的计算机与除IP地址10.1.1.1之外的其他所有计算机在138、139和445端口上发送的所有通信,下面这个BPF过滤规则就能完成上述任务:

'host 192.168.0.1 and not host 10.1.1.1 and (port 138 or port 139 or port 445)'

常用的BPF基元有:

  • host id , dst host id , src host id
  • net id , dst net id , src net id
  • ether host id , ether dst host id , ether src host id
  • port id , dst port id , src port id
  • gateway id , ip proto id , ether proto id
  • tcp, udp, icmp, arp
  • vlan id 根据字节的值过滤数据包

BPF语言也可以用来检查帧内任意一个单字节字段(或多字节字段)的值是不是规定值。下面是一些例子:

ip[8]<64

这个过滤规则规定要抓取的是:所有自ip头偏移8个字节的那个单字节字段的值小于64的IP包。被检查的这个字段表示的是“包的存活时间”或称“TTL”。大多数Windows系统中TTL的默认值是128,所以这个过滤规则将丢弃局域网中所有来自Windows系统的流量,只获取所有来自Linux系统的流量(因为在LInux系统中TTL的默认起始值是64)

ip[9]!=1

这一过滤规则规定要抓取的是所有IP头部偏移9个字节的那个单字节字段的值不等于“1”的帧。因为IP头部偏移9个字节的这个字段表示的是嵌入协议,如果等于“1”则表示“ICMP”协议,所以这个过滤规则将抓取除ICMP包之外的所有流量。这一表达式也等价于基元“not icmp”。

icmp[0] = 3 and icmp[1] = 0

这个语句规定要抓取的是:所有ICMP头部偏移0个字节的那个单字节字段等于3,且偏移1个字段的单字节字段等于0的ICMP数据包。换而言之,这一过滤规则将只抓取ICMPtype为3,code为0的“网络不可达”消息。

tcp[0:2] = 31337

这个语句检查了一个多字节字段,它检查的是:TCP头部偏移0个字节起的一个多字节字段(2个字节),该字段表示的是TCP源端口。所以这个表达式就等价于BPF基元“src prot 31337”

ip[12:4] = 0xC0A80101

我们看到的这是一个4字节的比较,它检查的是IP头部偏移12个字节起的4个字节里存放的数据——源IP地址。注意这个表达式里使用了十六进制表示法。转换成十进制数字,它就是192.168.1.1(0xC0=192,0xA8=168,0x01=1)。所以这一过滤规则将捕获所有源IP地址为192.168.1.1的流量。

根据位(bit)的值过滤数据包

BPF语言还提供了一种方法让我们能检查更小的字段或精度更高的偏移量。具体做法是:我们先引用相关的字节,或多个字节,然后再用“位掩码”逐位地把我们需要检查的位分离出来。

假设要过滤所有IP头部中可选字段被启用的包(就是IP头的长度大于20个字节的包)。IP头部的低半个字节表示的是IP头的长度,以“word”(字)为单位(一个word等于4个字节)。我们只需要找出这半个字节的值大于5(5word*4个字节/word=20个字节)的包就等于找出所有IP头部大于20个字节的包了。具体做法是用位掩码“00001111”(或者0x0F)创建一个BPF过滤规>>>则,通过逻辑“与”运算提取目标值。

ip[0] & 0x0F > 0x05 与之类似,如果我们要找出所有“不分片”标志位(位于IP头部偏移6个字节位置上的一位二进制位)被置1的IP包,我们亦可用二进制位掩码“01000000”(0x40)来表示我们只关心IP头部偏移6个字节位置上那个第二最高位的bit值是是不是1。

在构造位掩码是,如果对应的那一位是我们需要检查的,那就用1表示,否则就用0表示。

ip[6] & 0x40 != 0

接下来我们尝试调用getSniffer方法。

sniffer = getSniffer('eth0','tcp port 80')
for ptime,data in sniffer:
    print ptime,data

这段代码中,调用getSniffer方法得到pcap对象,然后我们循环读取监听到的数据。 这里我在虚拟机运行这段代码,然后在从宿主机中访问网页,可以看到打印的数据,证明 监听成功。

图4

4.1.7 使用Scapy编写Sniffer

又到了强大的Scapy出场的时候了,通过前面章节的介绍,相信大家已经对它不陌生了,在 底层网络编程方面,Scapy机会是万能的存在。下面我们看看使用Scapy编写Sniffer的代码:

from scapy.all import *

def packetHandler(pkt):
    src=pkt[IP].src
    srcPort=pkt[IP].dst
    if src=='192.168.1.20':
        print 'ok'

sniff(filter='tcp and port 80',prn=packetHandler,iface='eth0')

先看上面这段简单的代码,最下面一行是调用的scapy的sniff方法,该方法就是用来监听 数据的,我们可以在scapy的交互窗口中使用help来查看sniff方法的说明。

sniff(count=0, store=1, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, *arg, **karg)
    Sniff packets
    sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets

      count: number of packets to capture. 0 means infinity
      store: wether to store sniffed packets or discard them
        prn: function to apply to each packet. If something is returned,
             it is displayed. Ex:
             ex: prn = lambda x: x.summary()
    lfilter: python function applied to each packet to determine
             if further action may be done
             ex: lfilter = lambda x: x.haslayer(Padding)
    offline: pcap file to read packets from, instead of sniffing them
    timeout: stop sniffing after a given time (default: None)
    L2socket: use the provided L2socket
    opened_socket: provide an object ready to use .recv() on
    stop_filter: python function applied to each packet to determine
                 if we have to stop the capture after this packet
                 ex: stop_filter = lambda x: x.haslayer(TCP)

参数说明已经很清楚了,过滤数据包可以使用filter,lfilter,stop_filter,filter是过滤表达式, lfilter 和stopfilter 是python函数。前两者作用一样,用来过滤我们需要的数据包,或者 是一个终止监听的判断条件。 prn是数据包的处理函数,我们要在此做数据包的解析,分析等工作。 数据包的解析,我们会在下一节做详细的讲解,大家在练习的时候一定要结合以太网数据包的格式来 调试分析数据包对象,相互加深,会有事半功倍的效果。

图5

上面代码的运行结果如下:

图6

4.1.8 小结

本节主要讲了如何利用Pypcap和Scapy来编写Sniffer,完成了监听数据的功能,当然这只是 完成了前置功能,嗅探器的核心是数据分析。下一节我将从协议分析、数据内容分析、数据汇总 三个方面为大家讲解。请关注《Python 黑帽编程4.2 Sniffer之数据分析》。

本文分享自微信公众号 - 玄魂工作室(xuanhun521),作者:玄魂工作室

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-10-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python黑帽编程3.0 第三章 网络接口层攻击基础知识

    首先还是要提醒各位同学,在学习本章之前,请认真的学习TCP/IP体系结构的相关知识,本系列教程在这方面只会浅尝辄止。 本节简单概述下OSI七层模型和TCP/I...

    用户1631416
  • Python黑帽编程2.1 Python编程哲学

    本节的内容有些趣味性,涉及到很多人为什么会选择Python,为什么会喜欢这门语言。我带大家膜拜下Python作者的Python之禅,然后再来了解下Python的...

    用户1631416
  • 某市企业网站安全防护情况调查分析

    本文由Tide安全团队成员“TideSec”首发于FreeBuf TideSec专栏:

    用户1631416
  • 使用代码为textview设置drawableLeft

    xml中的textView中设置android:drawableLeft: <TextView          android:id="@+id/bookTi...

    欢醉
  • 加密劫持的潜在风险

    对于任何企业而言,隐私和安全性始终是关注的焦点。攻击者试图渗透到公司系统并窃取重要业务和客户信息,攻击的种类层出不穷,攻击速度也越来越快。网络攻击似乎永不停歇。...

    FB客服
  • DTU助力于智能配电房监控系统

    长期以来,配电房管理工作一直是供电系统运行管理可靠性的薄弱环节之一,一些配电房开关跳闸和配电房环境过热影响设备运行、配电房水浸导致设备损坏、配电房设备被盗等,既...

    用户5395653
  • 显示硬件信息的Linux命令【Linux-Command line】

    可能有很多原因导致你需要查找有关计算机硬件的详细信息。 例如,如果需要帮助修复某些问题并在在线论坛上发布请求,人们会立即询问你有关计算机的详细信息。 再者,如果...

    QRosie
  • [PySimpleGUI界面学习](十三)多页面控件和程序打包

    <!--more--> # 简述 到目前为止,我们已经介绍了`PySimpleGUI`中大多数控件,也熟悉了用`PySimpleGUI`来开发一个用户界面的方...

    王荣胜
  • 一个 WebSocket 服务器是如何开发出来的?

    WebSocket 协议是为了解决 http 协议的无状态、短连接(通常是)和服务端无法主动给客户端推送数据等问题而开发的新型协议,其通信基础也是基于 TCP。...

    全菜工程师小辉
  • ECMAScript 6入门 - let和const命令详解

    let命令 基本用法 ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。 'use strict'...

    laixiangran

扫码关注云+社区

领取腾讯云代金券