目录
简介 什么是Scapy?
基本介绍 怎么用Scapy?
Scapy的基本操作
Scapy模块中的函数
Scapy 简单实例
相比前两个模块,这个模块的额内部已经实现了大量的网络协议(DNS、ARP、IP、TCP、UDP等),可以用来编写非常灵活的工具。
在很多优秀的网络扫描和攻击工具都用到了这个模块,而自己的程序中也可以用这个模块来实现对网络数据包的发送、监听和解析。这个模块相比于Nmap来说,更加的底层,可以直观地了解到各种扫描和攻击行为。例如,检测某端口是否开放,只需要给Nmap提供一个端口号,而Nmap就会返回一个开或者关闭的结果。但是并不清楚具体是怎么实施的。而Scapy就会对网络的问题进行深入的研究,同样的功能,Scapy只会把收到的数据包返回给你,并不会告诉你这意味着什么,一切需要使用者自行判断。
举个显示例子,当你需要在外面吃饭时,会给你一份各种特色菜单,而服务员只会告诉你那些菜好吃,那么Nmap就相当于服务员,替你搞定一切,也会根据他的经验告诉你结果,而Scapy则相当于一个厨师,它只会告诉你这个菜由那些菜品制作,怎么制作。但是具体好不好吃还得你自己来评价。
kali中可以直接使用Scapy模块,已经被集成为一个工具使用。
在Scapy中,每一个协议就是一个类,只需要实例化一个协议类,就可以使用该协议的数据包。例如创建一个IP的数据包,就可以使用如下命令。
ip=IP()
ip数据包最重要的属性就是源地址和目的地址,这两个属性可以用src和dst来设置,例如构造一个发往“192.168.65.1”的数据包,就可以用如下语句。
ip=IP(dst=”192.168.65.1”)
这个dst不仅可以为一个ip也可以为一个ip的范围。例如
target=”192.168.65.0/24”
ip=IP(dst=target)
ip
使用[p for p in ip]来查看每一个数据包。
Scapy采用的是分层的形式来构造数据包,通常最下面的协议为Ether,然后是IP,接着是TCP或者UDP。
来介绍一下Ether()。这个函数可以用来设置发送方和接收方的MAC地址。现在来生成一个广播数据包。执行的命令如下。
Ether(dst=”ff:ff:ff:ff:ff:ff”)
Scapy中的分层可以符号“/“实现,一个数据包是由多层协议组合而成,那么这些协议就可以用”/”分开,按照协议由底层向上排列,接下来来完成一个TCP的数据包。
Ether()/IP()/TCP()
加入要构造一个HTTP数据包,也可以使用这种方式
IP()/TCP()/”GET /HTTP/1.0\r\n\r\n”
Scapy中使用频率最高的还是Ether、IP、TCP、UDP,如何查看这些类所具有的属性呢?
使用ls(Ether())来看Ether类的属性。
可以对这里面的属性进行设置,例如修改type为36888
除了这些对应的协议类和它们的属性之外,还需要一些可以完成各种功能的函数。我们刚才使用IP()创建的仅仅是数据包,但是并没有对其进行操作,接下来简单介绍一下各类函数,来对数据包进行操作。
首先看看怎么将数据包发出去,先简单来说send()/sendp()函数,这两个的区别在于send()工作在第三层,而sendp()工作在第二层。简单地说,send()是用来发送IP数据包的,而sendp()是用来发送Ether数据包的。
比如,构造一个目的地址为“192.168.65.142”的ICMP数据包,将其发送出去,可以使用如下语句
send(IP(dst = “192.168.65.142”)/ICMP())
执行的结果如图
如果发送成功,下方会有一个Sent 1 packets
注意一点,这两个函数都是只发不收,没有能力处理该数据包的回应包。也就是只发不收。
如果希望发送一个内容是随机填充的数据包,又要保证数据包的正确性,那么可以是fuzz()函数,可以使用如下命令来创建一个发送192.168.65.1的TCP数据包
IP(dst=’192.168.65.1’)/fuzz(TCP())
在网络的各种应用中,需要的是将创建好的数据包发出去,还要接受这些数据包的应答数据包,这一点在网络扫描中非常重要,在Scapy中提供了三个用来发送和接受的数据包函数,分别是sr()、sr1()和srp(),其中sr()和sr1()主要用于第三层,例如IP和ARP等,srp()主要用于第二层。
sr(IP(dst="192.168.65.1")/ICMP())
接收这些数据包的应答数据包。三个用来发送和接收数据包的函数
sr()函数返回的数据包是两个列表,第一个列表收到了应答的包和对应的应答,第二个列表收到了未应答的包。所以可以使用两个列表来保存sr()的返回值
这里使用ans和unans来保存sr()的返回值,因为发出去的是一个ICMP的请求数据,也收到了一个返回包,所以在这个包和结果被保存在ans列表里,使用ans.summary()可以查看数据包的内容。
而sr1()和sr()的函数作用基本上是一致的,但是只返回一个应答的包。只需要使用一个列表就可以保存这个函数的返回值。例如
l=sr1(IP(dst="192.168.65.142")/ICMP())
可以利用sr1()函数来测试目标的某个端口是否开放,采用半开扫描(SYN)的办法。
结果如图
观察flags处有回应,则说明这台主机的80端口是开放的。
另外一个常用的函数是sniff(),这个函数可以在自己的程序中捕获经过本机网卡的数据包
随便打开了一个网页,显示结果如图。
这个函数的强大在于可以使用参数filter对数据包进行过滤。例如,指定只捕获192.168.65.142相关的数据包,就可以使用“host 192.168.65.142”
sniff(filter=”host 192.168.65.142”)
同样的可以过滤指定的数据包
sniff(filter=”icmp”)
如果要同时满足多个条件可以使用关系运算符”or”“and”来表达:
sniff(filter=”host 192.168.65.142 and icmp”)
另外,两个很重要的参数iface、count。iface可以用来指定要监听的网卡。
sniff(iface=“eth1”)
表示用eth1来进行监听
而count则用来指定监听道的数据包数量,达到指定的数量会停止监听,例如,只希望监听到三个数据包就停止:
sniff(count=3)
综上,目前需要创建一个在网卡eth0上监听源地址或者目的地址为192.168.65.142的ICMP数据包,当收到这样的数据包为三个时,停止监听。
sniff(filter)
开启一个新的终端,然后ping一下该地址。
在Scapy中查看上一条执行的内容可以使用“_”。
接下来看看结果。
其中的nsummary()的作用时以摘要的形式,显示出x的内容,长度为一行。
需求:
使用Scapy来实现一次ACK类型的端口扫描,对192.168.65.142的21、22、23、80、88、135、443、445这8个端口是否频闭进行扫描,采用ACK扫描模式。
这里简单分析一下,使用Scapy向目标发送了8个标志位置为”A“的TCP数据包,按照TCP三次握手的规则,如果目标端口没有被过滤,发出的数据包就会得到回应,否则不会有回应。根据Scapy的设计规则,查看最后ans中是否存在未被过两次的端口即可。
代码如下
from scapy.all import IP,TCP,sr
ans,unans=sr(IP(dst="192.168.65.142")/TCP(dport=[21,22,23,80,88,135,443,445],flags="A"))
for s,r in ans:
if s[TCP].dport == r[TCP].sport:
print str(s[TCP].dport) + " is unfiltered"
需求:使用Scapy模块设计一个判断端口是否开放的扫描器。
简单分析一下,如果一个端口被屏蔽,那么不会产生任何响应报文。如果端口处于开放状态,在它收到syn数据包后,会返回一个ack数据包,如果端口关闭状态,收到syn数据包后,会返回一个rst数据包。如果返回值为0x012(SYN,ACK),目标端口为开放状态,如果flags的值为0x014那么端口为关闭状态。还要特别说明一下为啥要用fuzz函数,不过不适用fuzz()来填充数据包,可能会导致目标端口不响应,从而导致无法对端口的状态进行判断。
from scapy.all import fuzz,TCP,IP,sr
ans,unans =sr(IP(dst="192.168.65.142")/fuzz(TCP(dport=80,flags="S")))
for s,r in ans:
if r[TCP].flags==18:
print str(s[TCP].dport) + " is open"
if r[TCP].flags==20:
print str(s[TCP].dport) + " is closed"
终于把基础模块弄完了。下一次更新的就要按照渗透测试步骤,一步一步总结该步会用到的工具,技巧,和python的应用,不出意外会分三次更新。