Scapy的基本操作
1.IP()类型数据包
在Scapy中,每一个协议就是一个类。只需要实例化一个协议类,就可以创建一个该协议的数据包。例如,如果要创建一个IP类型的数据包,就可以使用如下命令。
ip = IP()
ip.show()
运行结果:
IP数据包最重要的属性就是源地址和目的地址,这两个属性可以使用src和dst来设置。
例如,要构造一个发送“192.168.43.1”的IP数据包,可以使用下面代码:
ip = IP(dst="192.168.43.1")
ip.show()
运行结果:
这个目标的dst的值可以是一个IP地址,也可以是一个IP范围,例如192.168.43.0/24,这时产生的就不是1个数据包了。而是256个其中包括了192.168.43.0 最后以 192.168.43.255 结束。
ip_range = "192.168.43.0/24"
ip = IP(dst=ip_range)
for i in ip:
i.show()
部分运行结果: 2.Ether协议 Scapy采用分层的形式来构造数据包,通常最下面的一个协议为Ether,然后是IP,再之后是TCP或者UDP。
IP()函数无法用来构造ARP请求和应答数据包,所以这时可以使用Ether(),这个函数可以设置发送方和接收的MAC地址。
那么现在来产生一个广播数据包,执行的命令如下:
data = Ether(dst="ff:ff:ff:ff:ff:ff")
data.show()
运行结果如下:
当我们想要构造一个TCP数据包时。 我们可以用Ether()/IP()/TCP()来完成一个TCP数据包。
data = Ether()/IP()/TCP()
data.show()
想要查看Ether()类和IP()类的属性可以使用ls(Ether())和ls(IP())进行查看
Scapy模块中的函数
Scapy中提供了多个用来完成发送数据包的函数,首先来看一下其中的send()和sendp()。
这两个函数的区别在于send()工作在第三层,而sendp()工作在第二层。
简单来说,send()是用来发送IP数据包的,而sendp()是用来发送Ether数据包的。
例如,构造一个目的地址为“192.168.43.1”的ICMP数据包,并将其发送出去,可以使用下面的代码进行发送。
data = IP(dst="192.168.43.1") / ICMP()
send(data)
当我们发送成功时就会显示“Sent 1 packets”等字样。 当我们使用Ether()时就需要使用sendp()进行发送了。
data = Ether(dst="5a:0e:ec:04:59:d3")
send(data)
这个里的目的地址我填写的是MAC地址。
同样也会回显“Sent 1 packets”等字样
值得注意的是,这两个函数的特点是只发不收,也就是说只会将数据包发送出去,但是没有能力处理该数据包的回应包。
在网络的各种应用中,需要做的不仅是将创建好的数据包发送出去,也需要接收这些数据包的应答数据包,这一点在网络扫描中尤为重要。
在Scapy中提供了三个用来发送和接收数据包的函数,分别是sr(),sr1(),srp(),其中,sr()和sr1()主要用于第三层,例如IP和ARP等,而srp()用于第二层。
这里仍然向192.168.43.1发送一个ICMP数据包来比较一下sr()和send()的区别。
1. sr()
data = IP(dst="192.168.43.1") / ICMP()
sr(data)
运行结果:
data = IP(dst="192.168.43.1") / ICMP()
print(sr(data))
运行结果: 我们用print进行输出时会发现有两个元素,所以我们需要使用两个变量进行存储。
data = IP(dst="192.168.43.1") / ICMP()
ans, unans = sr(data)
ans.summary()
使用summary()进行查看数据包里的内容
2. sr1()
data = IP(dst="192.168.43.1") / ICMP()
sr1(data)
运行结果:
这里我们可以发现使用sr()和sr1()回显的结果都是相同的,同样都是有4个应答。
使用summary()进行查看数据包里的内容
data = IP(dst="192.168.43.1") / ICMP()
print((sr1(data).summary()))
例如,我们想要探测某个主机的端口是否开放,采用半开扫描(SYN)的办法
data = IP(dst="192.168.43.1") / TCP(dport=80,flags="S")
ans, unans = sr(data)
ans.summary()
运行结果: 我们运行之后可能对下列的输出结果有些不太明白,其实这里的整体意思是本地20端口向目标80端口发起一个SYN,当目标收到时就会回应一个SYN+ACK给我们本地,这里很明显它是收到了,并且还回复了,证明目标端口是打开的,关闭的不会有任何回应。
IP / TCP 192.168.43.156:ftp_data > 192.168.43.1:https S ==> IP / TCP 192.168.43.1:https > 192.168.43.156:ftp_data RA
利用Scapy进行端口屏蔽探测
在此之前我们先看看这几个图
使用Scapy来实现一次ACK类型的端口扫描,例如对192.168.43.1的21、23、135、443、445这5个端口是否被屏蔽进行扫描,注意是屏蔽而不是关闭,采用ACK扫描模式,可以构造如下的代码:
from scapy.all import *
port = [21, 23, 135, 443, 445]
data = IP(dst="192.168.43.1") / TCP(dport=port, flags="A")
ans, unans = sr(data)
ans.summary()
for s, r in ans:
print("发送:" + s.summary())
print("回复:" + r.summary())
for s, r in ans:
if s[TCP].dport == r[TCP].sport:
print("未过滤端口:" + str(s[TCP].dport))
运行结果: