在本章中,我们将介绍以下配方:
- 简易端口扫描仪
- IP 范围/网络扫描仪
- 隐形扫描
- 鳍扫描
- 圣诞节扫描
- TCP 确认扫描
- 兰斯坎
在渗透测试和网络分析中,网络扫描程序在获取本地网络中可用的主机以及这些主机上运行的应用程序的详细信息方面发挥着重要作用。网络扫描有助于识别主机上运行的可用 UDP 和 TCP 网络服务,也有助于确定主机正在使用的操作系统(OSs。
端口扫描程序用于检查服务器或主机上是否有打开的端口。它有助于攻击者识别主机上运行的服务,并利用漏洞(如果存在)进行攻击。
我们可以使用socket
模块用 Python 编写一个简单的端口扫描程序。socket
模块是 Python 中默认的底层网络接口。
我们可以使用socket
模块创建一个简单的端口扫描仪,步骤如下:
- 创建一个名为
port-scanner.py
的新文件,并在编辑器中打开它。 - 导入所需的模块,如下所示:
import socket,sys,os
将socket
模块与sys
和os
模块一起导入
- 现在,我们可以为扫描仪定义变量:
host = 'example.com'
open_ports =[]
start_port = 1
end_port = 10
这里我们定义了计划扫描的起始端口和结束端口
- 从域名获取 IP:
ip = socket.gethostbyname(host)
这里我们在socket
模块中使用gethostbyname
方法。这将返回域的 IP
- 现在我们可以向
probe
端口写入一个函数:
def probe_port(host, port, result = 1):
try:
sockObj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockObj.settimeout(0.5)
r = sockObj.connect_ex((host, port))
if r == 0:
result = r
sock.close()
except Exception ase:
pass
return result
这里我们创建一个名为sockObj
的套接字对象,并尝试将其连接到端口。如果连接成功,则端口打开。创建的socket
对象使用 IPv4 套接字系列(AF_INET
)和 TCP 类型连接(SOCK_STREAM
)。对于 UDP 类型的连接,我们必须使用SOCK_DGRAM
。
最后,它将结果作为函数的输出返回。
- 现在我们将为循环编写一个循环,在端口范围内迭代,并用
probe_port
方法探测端口:
for port in range(start_port, end_port+1):
sys.stdout.flush()
print (port)
response = probe_port(host, port)
if response == 0:
open_ports.append(port)
if not port == end_port:
sys.stdout.write('\b' * len(str(port)))
如果端口打开,则结果将添加到列表open_port
- 最后,按如下方式打印结果列表:
if open_ports:
print ("Open Ports")
print (sorted(open_ports))
else:
print ("Sorry, No open ports found.!!")
- 现在,我们可以尝试更改前面的脚本以扫描默认端口列表。
为此,我们将定义一个默认端口列表:
common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110,
123, 137, 138, 139, 143, 156, 161, 389, 443,
445, 500, 546, 547, 587, 660, 995, 993, 2086,
2087, 2082, 2083, 3306, 8443, 10000
}
另外,我们将循环更改为调用probe_port
,如下所示:
for p in sorted(common_ports):
sys.stdout.flush()
print p
response = probe_port(host, p)
if response == 0:
open_ports.append(p)
if not p == end_port:
sys.stdout.write('\b' * len(str(p)))
我们可以使用 ICMP 数据包创建网络扫描仪。由于 ICMP 不是 IP 协议,我们必须直接访问网络堆栈。因此,这里我们可以使用 Scapy 生成 ICMP 数据包并将其发送到主机。
要开始抓取,我们必须安装所需的 Python 包。这里我们使用 Scapy 生成数据包。要安装 Scapy,我们可以使用pip
。在使用 Python3 时,请确保为 Python3 安装 Scapy。同时安装其依赖模块netifaces
:
pip3 install scapy-python3
pip3 install netifaces
以下是使用scapy
模块创建简单网络扫描仪的步骤:
- 创建一个名为
network-scanner.py
的文件,并在编辑器中打开它。 - 导入脚本所需的模块:
import socket, re
from scapy.all import *
- 为了获得系统的本地 IP,我们在
socket
模块中使用getsockname
方法。但是,它需要一个连接。因此,我们创建一个 UDP 套接字连接以连接到 Google DNS,并使用此连接枚举本地 IP:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
- 现在,我们提取本地 IP 并用正则表达式截断最后的 IP 数字:
end = re.search('^[\d]{1,3}.[\d]{1,3}.[\d]{1,3}.[\d]{1,3}', ip)
create_ip = re.search('^[\d]{1,3}.[\d]{1,3}.[\d]{1,3}.', ip)
- 现在创建一个函数来生成 ICMP 数据包并将其发送到主机。这里我们使用 Scapy:
def is_up(ip):
icmp = IP(dst=ip)/ICMP()
resp = sr1(icmp, timeout=10)
if resp == None:
return False
else:
return True
- 创建另一个功能检查 IP 是否为环回(
127.0.0.1
:
def CheckLoopBack(ip):
if (end.group(0) == '127.0.0.1'):
return True
- 现在,通过迭代最后的 IP 数字,对网络中的所有 IP 运行 LAN 扫描:
try:
if not CheckLoopBack(create_ip):
conf.verb = 0
for i in range(1, 10):
test_ip = str(create_ip.group(0)) + str(i)
if is_up(test_ip):
print (test_ip + " Is Up")
except KeyboardInterrupt:
print('interrupted!')
conf.verb = 0
将禁用 Scapy 中的详细模式,以避免来自 Scapy 的日志
- 确保以管理权限运行脚本,因为 Scapy 需要管理权限才能创建数据包:
sudo python3 network-scanner.py
隐形扫描是 TCP 扫描的一种形式。在这里,端口扫描程序创建原始 IP 数据包并将其发送到主机以监视响应。这种类型的扫描也称为半开放扫描或 SYN 扫描,因为它永远不会打开完整的 TCP 连接。这种类型的扫描仪创建一个 SYN 数据包并将其发送到主机。如果目标端口打开,主机将使用 SYN-ACK 数据包进行响应。然后,客户端将使用 RST 数据包进行响应,以在完成握手之前关闭连接。如果端口关闭但未过滤,目标将立即响应 RST 数据包。
要创建 SYN 扫描仪,我们将使用 Scapy 模块。它是一个强大的交互式数据包处理程序和库。
对于扫描端口,我们将向正在扫描的主机发送自定义数据包,并解析响应以分析结果。我们需要 Scapy 生成数据包并发送到主机。确保系统中安装了scapy
模块。
我们可以通过以下步骤创建 SYN 扫描仪:
- 创建一个名为
syn-scanner.py
的新文件,并在编辑器中打开它。 - 像往常一样,导入所需的模块:
from scapy.all import *
这将导入scapy
模块
- 现在我们可以声明变量,如果需要,我们还可以将这些变量作为参数传递:
host = 'www.dvwa.co.uk'
ip = socket.gethostbyname(host)
openp = []
filterdp = []
common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110,
123, 137, 138, 139, 143, 156, 161, 389, 443, 445, 500, 546, 547, 587, 660, 995, 993, 2086, 2087, 2082, 2083, 3306, 8443, 10000 }
- 现在,我们可以创建一个函数来检查主机是否启动:
def is_up(ip):
icmp = IP(dst=ip)/ICMP()
resp = sr1(icmp, timeout=10)
if resp == None:
return False
else:
return True
我们创建并向主机发送 ICMP 数据包。如果启动,主机将作出响应。
- 接下来,我们可以创建一个函数,使用 SYN 数据包扫描端口:
def probe_port(ip, port, result = 1):
src_port = RandShort()
try:
p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='F')
resp = sr1(p, timeout=2) # Sending packet
if str(type(resp)) == "<type 'NoneType'>":
result = 1
elif resp.haslayer(TCP):
if resp.getlayer(TCP).flags == 0x14:
result = 0
elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
result = 2
except Exception as e:
pass
return result
在这里,我们将一个随机端口设置为目标端口,然后使用源端口、目标端口和目标 IP 创建一个 SYN 数据包。然后我们将发送数据包并分析响应。如果响应类型为None
,则端口关闭。如果响应有 TCP 层,那么我们必须检查其中的标志值。标志有九个位,但我们检查控制位,控制位有六个位。他们是:
以下是 TCP 层的标头结构:
因此,如果标志值是 0x12,那么响应有 SYN 标志,我们可以考虑端口是打开的。如果值为 0x14,则标志为 RST/ACK,因此端口关闭。
- 然后,我们将检查主机是否已启动,循环浏览公共端口列表,如果主机已启动,则扫描每个端口:
if is_up(ip):
for port in common_ports:
print (port)
response = probe_port(ip, port)
if response == 1:
openp.append(port)
elif response == 2:
filterdp.append(port)
if len(openp) != 0:
print ("Possible Open or Filtered Ports:")
print (openp)
if len(filterdp) != 0:
print ("Possible Filtered Ports:")
print (filterdp)
if (len(openp) == 0) and (len(filterdp) == 0):
print ("Sorry, No open ports found.!!")
else:
print ("Host is Down")
将扫描公共端口列表中的每个端口,并在打印的列表之后将已识别的开放端口添加到开放端口列表中
- 确保使用
sudo
运行脚本,因为我们正在使用 Scapy,Scapy 需要管理员权限:
sudo python3 syn-scanner.py
SYN 扫描可能会被防火墙阻止。但是,设置了 FIN 标志的数据包可以绕过防火墙。下面是它的工作原理——对于 FIN 数据包,关闭的端口用 RST 数据包回复,而打开的端口忽略数据包。如果是类型为 3、代码为 1、2、3、9、10 或 13 的 ICMP 数据包,我们可能会推断端口已过滤,无法找到端口状态。我们可以使用 Scapy 创建 FIN 包并扫描端口。
我们可以创建一个 FIN 扫描仪,如下所示:
- 正如我们在上一个配方中所做的那样,我们必须创建另一个文件
fin-scanner.py
,并在编辑器中打开它。 - 然后导入所需的模块:
from scapy.all import *
- 正如我们对 SYN scanner 所做的那样,设置变量并创建函数来检查服务器是否已启动:
host = 'www.dvwa.co.uk'
ip = socket.gethostbyname(host)
openp = []
filterdp = []
common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110,
123, 137, 138, 139, 143, 156, 161, 389, 443,
445, 500, 546, 547, 587, 660, 995, 993, 2086,
2087, 2082, 2083, 3306, 8443, 10000
}
def is_up(ip):
icmp = IP(dst=ip)/ICMP()
resp = sr1(icmp, timeout=10)
if resp == None:
return False
else:
return True
- 现在我们可以创建探测端口的函数,如下所示:
def probe_port(ip, port, result = 1):
src_port = RandShort()
try:
p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='F')
resp = sr1(p, timeout=2) # Sending packet
if str(type(resp)) == "<type 'NoneType'>":
result = 1
elif resp.haslayer(TCP):
if resp.getlayer(TCP).flags == 0x14:
result = 0
elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
result = 2
except Exception as e:
pass
return result
在创建要发送的数据包时,我们将FIN
的标志更改为F
- 最后,我们将检查主机是否已启动,循环查看公共端口列表,如果主机已启动,则扫描每个端口:
if is_up(ip):
for port in common_ports:
print (port)
response = probe_port(ip, port)
if response == 1:
openp.append(port)
elif response == 2:
filterdp.append(port)
if len(openp) != 0:
print ("Possible Open or Filtered Ports:")
print (openp)
if len(filterdp) != 0:
print ("Possible Filtered Ports:")
print (filterdp)
if (len(openp) == 0) and (len(filterdp) == 0):
print ("Sorry, No open ports found.!!")
else:
print ("Host is Down")
使用 XMAS 扫描,我们将同时发送一个带有一组标志的 TCP 数据包(PSH、FIN 和 URG)。如果端口关闭,我们将获得 RST。如果端口已打开或已筛选,则服务器不会响应。它类似于 FIN 扫描,不同于包创建部分。
以下是使用 Scapy 创建圣诞节扫描仪的步骤:
- 创建我们为上一个配方创建的文件的副本(FIN 扫描。由于它非常相似,我们只需要更改数据包创建部分。
- 要创建并发送包含 PSH、FIN 和 URG 标志的数据包,请更新
probe_port
方法中的数据包制作部分,如下所示:
p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='FPU')
仅更新 flags 参数。在这里,我们将 PSH、FIN 和 URG 的标志设置为FPU
。
确认标志扫描有助于验证服务器是否被防火墙、IP 或其他网络安全控制阻止。在 FIN 扫描中,我们将发送一个 TCP ACK 数据包。无响应或 ICMP 错误表明存在有状态防火墙,因为端口已过滤,如果我们返回 RST-ACK,则无状态防火墙:
使用 Scapy 创建 TCP 确认扫描程序的步骤如下:
- 像往常一样,导入所需的模块并设置变量。另外,定义检查主机状态的方法:
from scapy.all import *
# define the host, port
host = 'rejahrehim.com'
ip = socket.gethostbyname(host)
port = 80
# define the method to check the status of host
def is_up(ip):
icmp = IP(dst=ip)/ICMP()
resp = sr1(icmp, timeout=10)
if resp == None:
return False
else:
return True
- 要发送带有
ACK
标志的 TCP 数据包,请更新上一配方中的probe_port
方法,如下所示:
def probe_port(ip, port, result = 1):
src_port = RandShort()
try:
p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='A', seq=12345)
resp = sr1(p, timeout=2) # Sending packet
if str(type(resp)) == "<type 'NoneType'>":
result = 1
elif resp.haslayer(TCP):
if resp.getlayer(TCP).flags == 0x4:
result = 0
elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):
result = 1
except Exception as e:
pass
return result
这里我们创建一个 TCP ACK 数据包并将其发送到主机
- 最后,运行扫描仪,如下所示:
if is_up(ip):
response = probe_port(ip, port)
if response == 1:
print ("Filtered | Stateful firewall present")
elif response == 0:
print ("Unfiltered | Stateful firewall absent")
else:
print ("Host is Down")
LanScan 是一个 Python 3 模块,有助于扫描给定的本地网络。它可以列出所有设备及其打开的端口。LanScan 还可以帮助获取有关网络接口和网络的信息。
我们可以使用pip
安装lanscan
:
pip3 install lanscan
以下是 LanScan 的一些使用案例:
- LanScan 有一些选项可用于扫描 LAN。要了解系统中可用接口的详细信息,我们可以使用
interfaces
选项:
sudo lanscan interfaces
这将打印可用的接口,如下所示:
- 我们可以使用 network 命令获取已连接网络的列表:
sudo lanscan networks
- 我们可以从终端窗口开始本地网络扫描。它需要管理员权限:
sudo lanscan scan
在这里,它将列出 LAN 网络中的 IP 地址和每个系统中打开的端口