- Scapy模块文件
- 关于Scapy
- 基本用法
- 采用分层形式来构造数据包
- Scapy模块中的函数
- send()和sendp()
- fuzz()函数
- sr(),sr1()和srp()
- sniff()
- iface、count参数
- 常用简单实例
- 设计一个端口是否开放的扫描器。
- 情报收集
- 基于ARP的活跃主机发现技术
- 基于ICMP的活跃主机发现技术
- 编写一个利用ICMP实现的活跃主机扫描程序,
- 基于TCP的活跃主机发现技术
- 编写一个利用TCP实现的活跃主机扫描程序
- 基于UDP的活跃主机发现技术
- Scapy是一个由Python语言编写的强大工具,它是大量程序编写人员最喜爱的一个网络模块。
- 也可以在自己的程序中使用这个模块来实现对网络数据包的发送、监听和解析。
- 这个模块相比起Nmap来说,更为底层。可以更为直观地了解到网络中的各种扫描和攻击行为,例如,要检测某一个端口是否开放,只需提供给Nmap一个端口号,而Nmap就会给出一个开放或者关闭的结果,但是并不知道Nmap是怎么做的。
- 如果想对网络中的各种问题进行深入研究,Scapy无疑是一个更好的选择,可以利用它来产生各种类型的数据包并发送出去,Scapy也只会把收到的数据包展示给你,而并不会试图解释收到的数据包,解释结果可以帮助那些不知道什么是端口扫描的用户,但是弊大于利,因为这对于结果是一种主观的解释。可能的结果就是它们可以自己解释,知识丰富的用户将试图反向还原这个工具的解释以得到引起这个解释的真正原因。不幸的是,在这个过程中有大量的信息丢失。
- Scapy提供了和Python一样的交互式命令行。Scapy可以作为Python的一个模块存在,但是Scapy本身就是一个可以运行的工具,它自己具备一个独立的运行环境,因而可以不在Python环境下运行。
- 在Kali Linux 中已经集成了Scapy,既可以在Python环境中使用Scapy,也可以直接使用它。启动一个终端,输入命令“scapy”,就可以启动Scapy环境,如图
- 在Scapy中,每一个协议就是一个类。
- 只需要实例化一个协议类,就可以创建一个该协议的数据包。
- 例如,如果要创建一个IP类型的数据包,就可以使用如下命令
ip = IP()
。
- IP数据包最重要的属性就是源地址和目的地址,这两个属性可以使用src和dst来设置。例如,要构造一个发往“192.168.1.101”的IP数据包,可以使用
ip = IP(dst="192.168.1.101")
语句。
- 这个目标dst的值可以是一个IP地址,也可以是一个IP范围,例如192.168.1.0/24,这时产生的就不是1个数据包,而是256个数据包。
- 如果要查看其中每一个数据包,可以使用
[p for p in ip]
-
通常最下面的一个协议为Ether,然后是IP,再之后是TCP或者是UDP。
-
IP()函数无法用来构造ARP请求和应答数据包,可以使用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"
-
ls()函数查看一个类所拥有的属性
- 使用
ls(Ether())
来查看Ether类属性
- 使用
ls(IP())
来查看IP类的属性
- 使用
-
可以对这里面的属性进行设置,例如:将ttl的值设置为32,可以使用如下方式
IP(src="192.168.1.1", dst="192.168.1.101", ttl=32)
send() 工作在第三层,发送IP数据包
sendp() 工作在第二层,发送Ether数据包
例如,构造一个目的地址为"192.168.1.101"的ICMP数据包,并将其发送出去,可以使用语句
send(IP(dst="192.168.1.101")/ICMP())
#注意,如果这个数据包发送成功,下方会有一个“Sent 1 packets.”的显示。
sendp(Ether(dst="ff:ff:ff:ff:ff:ff"))
注:这两个函数的特点是只发不收,只会将数据包发送出去,但是没有能力处理该数据包的回应包!!
如果希望发送一个内容是随机填充的数据包,而且又要保证这个数据包的正确性,那么可以是fuzz()函数。
例如,可以使用如下命令来创建一个发往192.168.1.101的TCP数据包。
IP(dst="192.168.1.101")/fuzz(TCP())
sr(),sr1()和srp()
-
在网络的各种应用中,需要做的不仅是将创建好的数据包发送出去,也需要接收这些数据包的应答数据包,这一点在网络扫描中尤为重要。
-
在Scapy中提供了三个用来 发送和接收数据包的函数,分别是sr()、sr1()和srp(),其中,sr()和sr1()主要用于第三层,例如IP和ARP等。而srp()用于第二层。
-
仍然向192.168.1.101发送一个ICMP数据包来比较一下sr()和send()的区别。
sr(IP(dst="192.168.1.101")/ICMP())
-
当产生的数据包发送出去之后,Scapy就会监听接收到的数据包,并将其中对应的应答数据包筛选出来,显示在下面。Reveived表示收到的数据包个数,answers表示对应的应答数据包。
-
sr()函数是Scapy的核心,它的返回值是两个列表,第一个列表是收到了应答的包和对应的应答,第二个列表是未收到应答的包。所以可以使用两个列表来保存sr()的返回值
-
sr()函数是Scapy的核心,它的返回值是两个列表
- 第一个列表是收到了应答的包和对应的应答,
- 第二个列表是未收到应答的包。所以可以使用两个列表来保存sr()的返回值
-
使用ans和unans来保存sr()的返回值,因为发出去的是一个ICMP的请求数据包,而且也收到了一个应答包,所以这个发送的数据包和收到的应答包都被保存到了ans列表中
-
使用ans.summary()可以查看两个数据包的内容,而unans列表为空。
-
sr1()函数跟sr()函数作用基本一样,但是只返回一个应答的包。只需要使用一个列表就可以保存这个函数的返回值。
例如,使用p来保存sr1(IP(dst=“192.168.26.6”)/ICMP())
的返回值,如图所示。
可以利用sr1()函数来测试目标的某个端口是否开放,采用半开扫描(SYN)的办法。
sr1(IP(dst="192.168.26.101")/TCP(dport=80,flags="S"))
192.168.26.101回应了发出的设置了SYN标志位的TCP数据包,这表明这台主机的80端口是开放的
这个函数可以在自己的程序中捕获经过本机网卡的数据包
这个函数最强大的地方在于可以使用参数filter对数据包进行过滤。
例如,指定只捕获与192.168.1.102有关的数据包,可以使用“host 192.168.1.102”:
sniff(filter=" host 192.168.1.102")
同样,也可以使用filter来过滤指定协议,例如,icmp类型的数据包:
sniff(filter="icmp")
如果要同时满足多个条件可以使用“and”“or”等关系运算符来表达:
sniff(filter=" host 192.168.1.102 and icmp")
iface、count参数
iface函数
指定所要进行监听的网卡
例如,指定eth1作为监听网卡sniff(iface="eth1")
count参数
用来指定监听到的数据包的数量,达到指定数量就会监听停止
例如,只希望监听到三个数据包就停止sniff(count=3)
-
设计一个综合性的监听器,它会在网卡eth0上监听源地址或者目的地址为192.168.1.102的icmp数据包,当收到了三个这样的数据包之后,就会停止监听。
首先在Scapy中创建如下监听器:sniff(filter="icmp and host 192.168.26.100“,count=3,iface="eth0")
正常情况下,是不会有去往或者来自192.168.1.102的icmp数据包的,所以这时候可以打开一个新的终端,然后在里面执行命令“ping 192.168.1.102”
然后在Scapy中使用组合键Ctrl+C结束捕获,这时可以看到已经捕获到三个数据包
如果需要查看这三个数据包内容,可以使用“”,在Scapy中这个符号表示是上一条语句执行的结果,
例如刚刚使用sniff捕获到的数据包,就可以用“”表示。a =_ a.nsummary()
刚刚使用过的函数
.summary()
用来以摘要的形式显示pkt的内容,这个摘要的长度为一行p = IP(dst="www.baidu.com") p.summary() "192.168.169.130>Net('www.baidu.com') hopopt"
使用Scapy来实现一次ACK类型的端口扫描
ACK扫描:扫描主机向目标主机发送ACK数据包。根据返回的RST数据包- 有两种方法可以得到端口的信息。
例如,对192.168.1.102 的 21、23、135、443、445 这5个端口是否被屏蔽进行扫描,注意是屏蔽不是关闭,采用ACK扫描模式,可以构造如下的命令方式。
ans,unans = sr(IP(dst="192.168.1.102")/TCP(dport=[21,23,135,443,445],flags="A"))
-
正常的时候,如果一个开放的端口会回应ack数据包,而关闭的端口会回应rst数据包。
-
在网络中,一些网络安全设备会过滤掉一部分端口,这些端口不会响应来自外界的数据包,一切发往这些端口的数据包都如同石沉大海。注意这些端口的状态并非是开放或者关闭,而是被屏蔽。
-
向目标发送了5个标志位置为“A”的TCP数据包。按照TCP三次握手的规则,如果目标端口没有被过滤,发出的数据包就会得到回应,否则没有回应。另外,根据Scapy的设计,ans列表中的数据包就是得到了回应的数据包,而unans中的则是没有得到回应的数据包,只需要分两次来读取这两个列表就可以得到端口的过滤结果
for s,r in ans: if s[TCP].dport == r[TCP].sport: print (str(s[TCP].dport) + " is unfiltered“)
也可以用类似的方法来查看被过滤的端口:
for s in unans: print str(s[TCP].dport) + " is filtered"
-
下面在Python中编写程序来实现一个查看端口是否被屏蔽的简单程序。首先导入需要使用的scapy模块中的函数:
from scapy.all import IP,TCP,sr
这里需要IP()和TCP()来产生所需要的数据包,sr()函数来发送,然后发送构造好的数据包,在Python交互式命令行中执行这个程序的结果如图所示。
- 如果一个端口处于屏蔽状态,那么它将不会产生任何响应报文。
- 如果一个端口处于开放状态,那么它在收到syn数据包之后,就会回应一个ack数据包。
- 反之,如果一个端口处于关闭状态,那么它在收到syn数据包之后,就会回应一个rst数据包。
-
先导入需要使用的模块文件,这次需要使用IP()、TCP()来创建数据包,使用fuzz()来填充数据包,使用sr()来发送数据包。
from scapy.all import fuzz,TCP,IP,sr
-
接下来产生一个目标为“192.168.26.100”的80端口的syn数据包,将标志位设置为“S”:
ans,unans = sr(IP(dst="192.168.26.100")/fuzz(TCP(dport=80,flags="S")))
-
接下来使用循环来查看,
如果r[TCP].flags==18,则表示返回数据包flags的值为0x012 (SYN,ACK)目标端口为开放状态。
如果r[TCP].flags==20,则表示返回数据包flags的值为0x014 (RST, ACK) 目标端口为关闭状态。for s,r in ans: if r[TCP].flags==18: print "This port is Open" if r[TCP].flags == 20: print "This port is Closed"
-
这里的“情报”指的是目标网络、服务器、应用程序的所有信息。
-
渗透测试人员需要使用资源尽可能地获取要测试目标的相关信息。
-
信息收集获得信息的方法可以分成两种:被动扫描和主动扫描。
- 被动扫描主要指的是在目标 无法察觉的情况下 进行的信息收集
- 主动扫描一般都是针对目标发送特制的数据包,然后根据目标的反应来获得一些信息。
-
扫描之后将会获得的信息包括:目标网络的结构,目标网络所使用设备的类型,目标主机上运行的 *** 作系统,目标主机上所开放的端口,目标主机上所提供的服务,目标主机上所运行的应用程序。
-
在开始Python编程之前先来简单介绍nmap这个工具的使用。这个工具的使用方法十分简单,只需要在终端中输入 nmap 加上 参数 即可完成
选择扫描目标的nmap语法如下所示。
(1)扫描指定IP主机:nmap 192.168.169.133
(2)扫描指定域名主机:nmap www.nmap.com。
(3)扫描指定范围主机:nmap 192.168.169.1-20。
(4)扫描一个子网主机:nmap 192.168.169.0/24。 -
对目标的端口进行扫描的nmap语法如下所示。
(1)使用TCP全开扫描:nmap -sT 192.168. 169.1。
(2)使用TCP半开扫描:nmap -sS 192.168. 169.1。
(3)使用UDP扫描:nmap -sU -p 123,161,162 192.168. 169.1。 -
对目标端口状态进行扫描的nmap语法如下所示。
(1)扫描一个主机的特定端口:nmap -p 22 192.168. 169.1。
(2)扫描指定范围端口:nmap -p 1-80 192.168. 169.1。
(3)扫描100个最为常用的端口:nmap -F 192.168. 169.1。 -
对目标的 *** 作系统和运行服务进行扫描的nmap语法如下所示。
(1)扫描目标主机上运行的 *** 作系统:nmap -O 192.168.169.1。
(2)扫描目标主机上运行的服务类型:nmap -sV 192.168.169.1。
ARP的中文名字是“地址解析协议”,主要用在以太网中。
需要明确的是,所有的主机在互联网中通信的时候使用的是IP地址,而在以太网中通信时使用的却是硬件地址(也就是常说的MAC地址)。
- 现在来编写一个利用ARP实现的活跃主机扫描程序,这个程序有很多种方式可以实现,首先借助Scapy库来完成。
-
其核心思想就是要产生一个ARP请求,首先查看Scapy库中ARP类型数据包中需要的参数
这里面的大多数参数都有默认值,其中,hwsrc和psrc分别是源硬件地址和源IP地址。
这两个地址不用设置,发送的时候会自动填写本机的地址。
唯一需要设置的是目的IP地址pdst,将这个地址设置为目标即可 -
另外,因为发送的是广播数据包,所以需要在Ether层进行设置,首先查看一下Ether的格式
这一层只有三个参数:
dst是目的硬件地址,
src是源硬件地址,这里面src会自动设置为本机地址。
所以只需要将dst设置为ff:ff:ff:ff:ff:ff即可将数据包发到网络中的各个主机上 -
下面构造一个扫描192.168.26.100的ARP请求数据包并将其发送出去
ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.26.100"),timeout=2)
-
对这个请求的回应进行监听,如果得到回应,那么证明目标在线,并打印输出这个主机的硬件地址:
ans.summary(lambda (s,r): r.sprintf("%Ether.src% %ARP.psrc%") )
- 如果发出这个数据包,但是没有收到这个数据包回应,则说明目标主机不在线
-
ICMP位于TCP/IP协议族中的网络层,它的目的是用于在IP主机、路由器之间传递控制消息。
-
ICMP中提供了多种报文,这些报文又可以分成两大类:差错报文和查询报文。其中,查询报文都是由一个请求和一个应答构成的。
-
ICMP查询报文有4种,分别是响应请求或应答、时间戳请求或应答、地址掩码请求或应答、路由器询问或应答。
-
Ping命令就是响应请求或应答的一种应用,我们经常会使用这个命令来测试本地与目标之间的连通性。
-
例如我们所在的主机IP为192.168.1.1,而通信的目标IP地址为192.168.1.2,如果要判断192.168.1.2是否为活跃主机,就需要向其发送一个ICMP请求,这个请求的格式如下。
IP层内容: 源IP地址:192.168.1.1 目的IP地址:192.168.1.2 ICMP 层内容: Type:8(表示请求)/0(表示应答)
-
借助Scapy库来完成。其核心思想就是要产生一个ICMP请求,首
-
先查看Scapy库中ICMP类型数据包中需要的参数,这一层和地址有关的参数有两个:dst是目的IP地址,src是源IP地址。
-
src会自动设置为本机地址。所以只需要将dst设置为“192.168.26.100”即可将数据包发到目标主机上。
接下来构造一个扫描192.168.26.100的ICMP请求数据包并将其发送出去。ans,unans=sr(IP(dst="192.168.26.100")/ICMP()) #对这个请求的回应进行监听,如果得到了回应,那么证明目标在线,并打印输出这个主机的IP地址。 ans.summary(lambda (s,r): r.sprintf("%IP.src% is alive") )
TCP(Transmission Control Protocol,传输控制协议)是一个位于传输层的协议。它是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP的特点是使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答TCP的三次握手SYN+ACK,并最终对对方的SYN执行ACK确认。这种建立连接的方法可以防止产生错误的连接.
TCP三次握手的过程如下所示。
在这一层中出现了“端口”的概念。“端口”是英文port的意译,可以认为是设备与外界通信交流的出口。端口可分为虚拟端口和物理端口,这里使用的就是虚拟端口,指的是计算机内部或交换机路由器内的端口,例如计算机中的80端口、21端口、23端口等。
这些端口可以被不同的服务所使用来进行各种通信,例如Web服务、FTP服务、SMTP服务等,这些服务都是通过“IP地址+端口号”来区分的
- 如果检测到一台主机的某个端口有回应,也一样可以判断这台主机是活跃主机。
- 如果一台主机处于活跃状态,那么它的端口即使是关闭的,在收到请求时,也会给出一个回应,只不过并不是一个“SYN+ACK”数据包,而是一个拒绝连接的“RST”数据包。
这个程序有很多种方式可以实现,首先借助Scapy库来完成。核心的思想就是要产生一个TCP请求,
首先查看Scapy库中TCP类型数据包中需要的参数
- 这里的大多数参数都不需要设置,需要考虑的是sport、dport和flags。
sport是源端口,
dport是目的端口,
flags是标志位,可能的值包括SYN(建立连接)、FIN(关闭连接)、ACK(响应)、PSH(有DATA数据传输)、RST(连接重置)。此处将flags设置为“S”,也就是SYN。另外,TCP并没有目标地址和源地址,所以需要在IP层进行设置。
构造一个发往192.168.1.2的80端口的SYN请求数据包并将其发送出去。
ans,unans=sr( IP(dst="192.168.26.*")/TCP(dport=80,flags="S") )
对这个请求的回应进行监听,如果得到了回应,就证明目标在线,并打印输出这个主机的IP地址。
ans.summary(lambda (s,r): r.sprintf("%IP.src% is alive") )
基于UDP的活跃主机发现技术
UDP全称是用户数据报协议,在网络中它与TCP一样用于处理数据包,是一种无连接的协议。在OSI模型中位于第4层——传输层,处于IP的上一层。
但基于UDP的活跃主机发现技术和TCP不同,UDP没有三次握手。
当向目标发送一个UDP数据包之后,目标是不会发回任何UDP数据包的。
不过,如果目标主机是处于活跃状态的,但是目标端口是关闭的时候,可以返回一个ICMP数据包,这个数据包的含义为“unreachable”
如果目标主机不处于活跃状态,这时是收不到任何回应的
接下来构造一个发往192.168.26.100的6777端口的UDP数据包并将其发送出去。
ans,unans=sr( IP(dst="192.168.26.100")/UDP(dport=6777) )
对这个请求的回应进行监听,如果得到了回应,当然这个回应是ICMP类型的,就证明目标在线,并打印输出这个主机的IP地址。
ans.summary(lambda (s,r): r.sprintf("%IP.src% is alive") )
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)