目录
简述信息收集
主机状态扫描
基于ARP的活跃主机发现
ARP协议分析
利用ARP实现活跃主机的扫描python程序
基于ICMP的活跃主机发现
ICMP协议分析
利用ICMP实现活跃主机的扫描python程序
基于TCP的活跃主机发现
TCP协议分析
利用TCP实现活跃主机的扫描python程序
基于UDP的活跃主机发现
UDP协议分析
利用UDP实现活跃主机的扫描python程序
信息收集主要分为两类,一种是被动扫描,一种是主动扫描。
什么叫被动扫描?指的是在目标无法察觉的情况下,进行的信息收集,例如,在找一个人的信息时候,可以上网百度这个人的名字,找到相关的信息,这就叫被动扫描。kali中集成了很多被动扫描的工具例如:Recon-NG、Shodan等等
相比被动扫描,主动扫描的范围小得多,一般都是针对目标发送特制的数据包,根据目标的反应来获得信息。这种扫描方式的技术性比较强,通常会使用专业的扫描工具来对目标进行扫描。扫描后获得的信息包括:目标的网络结构,目标网络所使用设备的类型,目标的操作系统,目标主机开放的端口,目标主机所提供的服务。
这就需要大量的用到nmap模块。nmap的使用非常简单,一般命令格式为nmap+参数即可完成。
一些基本语法如下:
nmap IP
nmap 域名
nmap ip-ip 范围扫描
nmap ip0/24 全网段扫描
对于特定的端口进行扫描的语法
nmap -p 端口号 ip
nmap -p 端口号-端口号 ip
对目标端口的状态进行扫描
nmap -sT ip //使用TCP的全开扫描
nmap -sS ip //使用TCP的半开扫描
nmap -sU -p 端口 ip 使用UDP扫描
关于什么是全开扫描什么是半开扫描和UDP扫描,这里建议访问
https://blog.csdn.net/wwl012345/article/details/96304163
前辈的文章查看即可。
对目标的操作系统和运行服务进行扫描
nmap -O ip //扫描目标主机的操作系统
nmap -sV ip //扫描目标主机的服务版本
首先提一个问题,我们怎么联网的?
很明显,这一切都要归功于网络协议。网络协议通常是按照不同的层次开发出来的,每个层次的功能也不同。目前的分层模型有OSI和TCP/IP两种。本系列文章全部以TCP/IP分层结构来讲解。
在日常生活中,我们想知道某人是否在线,我们可以在聊天软件中给他发一句,在吗?
正常情况下,他如果回复,在。那就表明对方在线。(不考虑特殊情况!)这个步骤在TCP协议中的实现就是通过三次握手。我们的半开扫描就是给对方发送一个SYN包,对方回复一个ACK则说明对方在线,如果收到RST则说明对面不存在。在三次握手的步骤里这只执行了第一步和第二步。如果执行第三步我给对面再回复一个ACK和RST的话,就说明执行了全开扫描。
这么说的意思是就是我们如果要知道对面是否活跃,就需要给对面发包,根据对面的回复来判断对面是否存在。
ARP的中文名字是“地址解析协议”,主要用于以太网中,而所有主机在互联网中的通信的时候使用的时IP地址,而在以太网中通信时使用的却是MAC地址。
目前,绝大多数网络应用都没有考虑过硬件地址大部分都是依靠IP地址来进行通信。
这个时候在以太网中并没有用IP地址进行通信,所以我们用到了一个ARP的协议,用来将IP地址和MAC地址进行相互转换。
如图所示,这个时候以太网内所有的主机IP地址已知,PC0要向PC1进行通信。却不知道PC1MAC地址,那么他们是怎么通信的呢?
这个时候就需要通过以太广播报文,向网络的每一台主机发送ARP请求。
协议类型:ARP Request
源主机IP地址:192.168.65.3
目的主机IP地址:192.168.65.2
源主机的硬件地址:44:44:44:44:44:44
目标主机的MAC地址:ff:ff:ff:ff:ff:ff
当其余主机接收到这个ARP请求的数据包之后,它会用自己的IP地址与包中头部目标主机的IP进行比较,如果不匹配,就不会有回应。这个时候若192.168.65.2的设备接收到这个请求,就会给发送IP的PC0主机回复一个ARP回应数据包。格式如下:
协议类型:ARP Reply
源主机IP地址:192.168.65.2
目的主机IP地址:192.168.65.3
源主机的硬件地址:22:22:22:22:22:22
目标主机的MAC地址:44:44:44:44:44:44
这个包不是广播包,当主机收到这个回应之后,就会把这个结果放在ARP缓存表中。缓存格式
IP地址 硬件地址 类型
192.168.65.2 22:22:22:22:22:22 动态
以后当PC0需要再次和PC1进行通讯时,只需要查询这个ARP的缓存表,找到对应的内容,按照这个硬件地址发送出去即可。
当目标主机与我们处于同一个以太网的时候,利用ARP进行扫描是最好的选择。
ARP扫描的图例:
第一步:向目标发送一个ARP Request
第二步:如果目标主机处于活跃状态,它一定会回复一个ARP Reply
第三步:如果目标主机处于非活跃状态,它不会给任何回应。
根据这些特性,下面来进行利用。
首先借用Scapy库来完成,核心思路就是产生一个ARP请求,然后发送出去,接着对回应进行监听,如果得到回应,证明主机在线,并且打印出主机的MAC地址。
根据Scapy的特性,我们需要
创建一个ARP的请求数据包并且将其发送出去
ans,unans=srp(Ether(dst=”ff:ff:ff:ff:ff:ff”)/ARP(pdst=”192.168.65.2”),timeout=3)
//这行代码中,我们分析一下,为什么既要用Ether,又要用ARP两个参数。
在ARP中我们只需要设定的只有目标地址也就是pdst,在Scapy中,只有第二次Ether参数可以用来发送MAC地址。所以我们用了Ether参数和ARP参数。所以这行代码的意思就是发送了一个ARP目标地址为192.168.65.2的广播报文。等待时间3秒。
监听请求的回应,如果有回应证明目标在线并且输出目的地址和MAC地址。
根据Scapy的特点,代码如下
关于怎么设置的
我们需要在scapy模块下
输入“ls(Ether)”即可查看所有的参数信息。然后根据我们的需要进行配置即可。后面都是这个思路,不再次重复。
如果在ans列表里面存在发送包和返回包,就说明这个主机存活,将他的主机IP地址和MAC输出。
完整的代码如下:
import sys
if len(sys.argv) !=2:
print "Usage
\n eg: py 192.168.65.1" sys.exit(1)
from scapy.all import *
ans,unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=sys.argv[1]),timeout=3)
for snd,rcv in ans:
print("Target is alive")
print rcv.sprint("%Ether.src% - %ARP.psrc%")
接下来用nmap模块进行操作
这个库的核心类为PortScanner,-PR表示使用了ARP,-sn表示测试主机状态
完整的代码如下:
import sys
if len(sys.argv) !=2:
print "Usage
\n eg: py 192.168.65.1" sys.exit(1)
import nmap
nm = nmap.PortScanner()
nm.scan(sys.argv[1],arguments='-sn -PR')
for host in nm.all_hosts():
print('------------------')
print('HOST : %s (%s)' %(host,nm[host].hostname()))
print('State : %s' % nm[host].state())
这个程序的执行结果如图:
ip部分可以设置一个主机,也可以设置一个网段。
在AptanaStudio3中设置IP方法为:
ARP的局限在于,仅仅能够扫描同一个网段的主机,对于不同网段的主机无法扫描。这里就需要用到其他的探测方法了。
ICMP的全称为(Internet Control Message Protocol),这种协议和他的名字一样,主要是为了发现和处理互联网中的错误。当然也可以用来利用进行主机发现。虽然相比ARP更为复杂,但是其扫描地原理都是一样的。
ICMP中有多个报文,这些报文又分为两大类:差错报文和查询报文。其中查询报文都是由一个请求和一个应答构成。其中查询报文都是由一个请求和一个应答构成的。如果向目标发送了一个请求包,收到了来自目标的回应,就可以判断,和ARP扫描的原理相同。
与ARP扫描不同的地方是,ICMP的查询报文有4中,分别是响应请求或应答、时间戳请求或应答、地址掩码请求或应答、路由器查询或应答。在实际应用中,主要用第一种,响应请求和应答。一般的经典应用就是ping。
如果要判断192.168.65.2是否为活跃主机,就需要对其发送一个ICMP请求,请求的内容如下:
IP层内容
源IP地址: 192.168.65.3
目的IP地址: 192.168.65.2
ICMP层内容
Type:8(表示请求)
如果192.168.65.2是处于活跃状态,它收到这个请求之后,就会给出一个回应,回应的内容如下:
IP层内容
源IP地址:192.168.65.2
目的IP地址: 192.168.65.3
ICMP层内容
Type:0(表示应答)
以图的形式来演示一下这个扫描过程。
第一步:向目标发送一个ICMP Request
第二步:如果目标主机处于活跃状态,在正常情况下,它就会回应一个ICMP Reply
注意一点,目前很多网安设备或机制会屏蔽ICMP,这种情况下,即使目标主机处于活跃状态,也收不到任何回应。
第三步:如果目标主机处于非活跃状态,它不会给出任何回应。
也就是说,只要收到了ICMP的回应,就可以判断该主机为活跃状态。
利用Scapy的核心思想就是产生一个ICMP的请求,并且发送出去。
ans,unans=sr(IP(dst=”192.168.65.3”)/ICMP())
接着对这个回应进行监听,如果得到了回应,就说明主机在线。
ans.summary(lambda(s,r):r.sprintf(“%IP.src% is alive”))
完整的代码如下:
import sys
if len(sys.argv) !=2:
print "Usage
\n eg: py 192.168.65.1" sys.exit(1)
from scapy.all import *
ans,unans=sr(IP(dst=sys.argv[1])/ICMP())
for snd,rcv in ans:
print rcv.sprint(“%IP.src% is alive")
使用nmap库来实现这个功能更简单。-PE表示使用ICMP,-sn表示只测试该主机的状态。在Nmap中使用ICMP进行扫描的语法格式为:
Nmap -PE -sn [ip]
其完整代码如下:
import sys
if len(sys.argv) !=2:
print "Usage
\n eg: py 192.168.65.1" sys.exit(1)
import nmap
nm = nmap.PortScanner()
nm.scan(sys.argv[1],arguments='-sn -PE')
for host in nm.all_hosts():
print('------------------')
print('HOST : %s (%s)' %(host,nm[host].hostname()))
print('State : %s' % nm[host].state())
TCP(Transmission Control Protocol 传输控制协议)是一个位于传输层的协议。它是一种面向连接的、可靠的、基于字节流的传输层通信协议。特点是通过三次握手协议建立连接。
其过程如下所示:
第一步:客户端发送SYN(SEQ=X)数据包给服务器端,进入SYT_SEND状态
第二步:服务器端收到SYN数据包,回应一个SYN(SEQ=y)+ACK(ACK=x+1)数据包,
进入SYN_RECV状态
第三步:客户端收到服务器端的SYN数据包,回应一个ACK(ACK=y+1)数据包,进入Established状态。三次握手完成,TCP客户端和服务器成功建立联系,可以进行传输。
TCP和上面的ARP、ICMP并不处于同一层,而是位于传输层。在这一层出现了端口的概念。可以认为是设备与外界进行通信交流的出口。端口分为虚拟端口和物理端口。这里指的是虚拟端口,指的是计算机内部或交换机路由器内的端口。例如常见端口:80、88、21、3306、443端口,这些服务都是通过“IP地址+端口号”来区分。
同样的,如果检测到某台主机的某个端口有回应,也一样可以判断这台主机是活跃主机,注意,如果一个主机是活跃的,那么即使端口是关闭的,在收到请求时也会给一个回应,数据包为“RST”
这样的话检测主机是否活跃时候,向端口发送一个SYN数据包,之后的情形可能有三种
第一种:主机发送的SYN数据包到达了目标的端口,但是目标端口关闭了,这时候会返回一个RST数据包。
第二种:主机发送的SYN数据包到达目标端口,而且目标端口开放。这时候会返回一个“SYN+ACK”数据包
第三种:主机发送的SYN数据包未到达目标,这时不会收到任何回应。
也就是说,只要收到了TCP的回应,就可以判断该主机为活跃状态。
利用Scapy的核心思想和上面一样,都是通过Scapy库,产生一个TCP请求,然后监听这个回应,如果得到了回应就说明,目标在线。
构建的TCP数据包格式如下:
ans,unans=sr(IP(dst=”192.168.65.2”)/TCP(dport=80,flags=”S”))
其完整代码如下:
import sys
if len(sys.argv) !=3:
print "Usage
\n eg: py 192.168.65.1 80" sys.exit(1)
from scapy.all import *
ans,unans=sr(IP(dst=sys.argv[1])/TCP(dport=int(sys.argv[2]),flags=”S”))
for snd,rcv in ans:
print rcv.sprint(“%IP.src% is alive")
使用nmap库来实现功能。在NMAP中使用-sT表示使用TCP这里不需要使用-sn选项了,因为这样会跳过端口扫描。在Nmap中使用TCP选项进行扫描的语法格式为:
nm.scan(“ip”,arguments=’-sT’)
完整代码如下:
import sys
if len(sys.argv) !=2:
print "Usage
\n eg: py 192.168.65.1" sys.exit(1)
import nmap
nm = nmap.PortScanner()
nm.scan(sys.argv[1],arguments='-sT')
for host in nm.all_hosts():
print('------------------')
print('HOST : %s (%s)' %(host,nm[host].hostname()))
print('State : %s' % nm[host].state())
TCP扫描的可靠性好比较有效。
UDP全称是用户数据报协议,在网络中和TCP同样用于处理数据包,是一种无连接的协议。UDP和TCP不同的是,当目标处于活跃状态,收到来自主机的一个UDP数据包后,目标不会返回任何UDP数据包,但是,当目标处于活跃状态,而目标端口是关闭的时候,可以返回一个ICMP数据表,含义为”unreacheable”
所以一般利用UDP时候,都会把端口尽量往大了写。
其过程如下图:
如果目标不处于活跃状态,这时是收不到任何回应的,其过程如下图:
就接下来按照我们之前的思路,构造一个发往192.168.65.142 6888端口的UDP数据包
ans,unans=sr(IP(dst=”192.168.65.142”)/UDP(dport=8888))
接下来进行监听即可。
其完整代码如下:
import sys
if len(sys.argv) !=3:
print "Usage
\n eg: py 192.168.65.1 80" sys.exit(1)
from scapy.all import *
ans,unans=sr(IP(dst= sys.argv[1])/UDP(dport=int(sys.argv[2]))
for snd,rcv in ans:
print rcv.sprint(“%IP.src% is alive")
使用nmap库来实现功能。在NMAP中使用-PU表示使用TCP这里也不需要使用-sn选项了,因为这样会跳过端口扫描。在Nmap中使用TCP选项进行扫描的语法格式为:
nm.scan(“ip”,arguments=’-PU’)
其完整代码如下:
import sys
if len(sys.argv) !=2:
print "Usage
\n eg: py 192.168.65.1" sys.exit(1)
import nmap
nm = nmap.PortScanner()
nm.scan(sys.argv[1],arguments='-PU')
for host in nm.all_hosts():
print('------------------')
print('HOST : %s (%s)' %(host,nm[host].hostname()))
print('State : %s' % nm[host].state())