第四章 指纹识别(三)
作者:Justin Hutchens
译者:飞龙
4.13 SNMPwalk SNMP 分析
SNMPwalk 是个更加复杂的 SNMP 扫描器,可以通过猜测 SNMP 团体字符串来收集来自设备的大量信息。SNMPwalk 循环遍历一系列请求来收集来自设备的尽可能多的信息。
准备
为了使用 SNMPwalk 来执行操作系统识别,你需要拥有开启 SNMP 并可以探测的远程系统。提供的例子使用 Windows XP。配置 Windows 系统的更多信息请参考第一章的“安装 Windows Server”秘籍。
操作步骤
为了执行 SNMPwalk,应该将一系列参数传给工具,包括被分析系统的 IP 地址,所使用的团体字符串,以及系统所使用的 SNMP 版本:
root@KaliLinux:~# snmpwalk 172.16.36.134 -c public -v 2c
iso.3.6.1.2.1.1.1.0 = STRING: "Hardware: x86 Family 6 Model 58 Stepping 9 AT/AT COMPATIBLE - Software: Windows 2000 Version 5.1 (Build 2600 Uniprocessor Free)"
iso.3.6.1.2.1.1.2.0 = OID:
iso.3.6.1.4.1.311.1.1.3.1.1
iso.3.6.1.2.1.1.3.0 = Timeticks: (56225) 0:09:22.25
iso.3.6.1.2.1.1.4.0 = ""
iso.3.6.1.2.1.1.5.0 = STRING: "DEMO-72E8F41CA4"
iso.3.6.1.2.1.1.6.0 = ""
iso.3.6.1.2.1.1.7.0 = INTEGER: 76
iso.3.6.1.2.1.2.1.0 = INTEGER: 2
iso.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1
iso.3.6.1.2.1.2.2.1.1.2 = INTEGER: 2
iso.3.6.1.2.1.2.2.1.2.1 = Hex-STRING: 4D 53 20 54 43 50 20 4C 6F 6F 70 62 61 63 6B 20 69 6E 74 65 72 66 61 63 65 00
iso.3.6.1.2.1.2.2.1.2.2 = Hex-STRING: 41 4D 44 20 50 43 4E 45 54 20 46 61 6D 69 6C 79
为了对开启 SNMP 的 Windows XP 系统使用 SNMPwalk,我们使用默认的团体字符串public
,以及版本2c
。这会生成大量数据,在展示中已经截断。要注意,通常所有被识别的信息都在所查询的 IOD 值后面。这个数据可以通过使用管道连接到cut
函数来移除标识符。
root@KaliLinux:~# snmpwalk 172.16.36.134 -c public -v 2c | cut -d "=" -f 2
STRING: "Hardware: x86 Family 6 Model 58 Stepping 9 AT/AT COMPATIBLE - Software: Windows 2000 Version 5.1 (Build 2600 Uniprocessor Free)"
OID: iso.3.6.1.4.1.311.1.1.3.1.1
Timeticks: (75376) 0:12:33.76
""
STRING: "DEMO-72E8F41CA4"
要注意, SNMPwalk 的输出中不仅仅提供了系统标识符。在输出中,可以看到一些明显的信息,另一些信息则是模糊的。但是,通过彻底分析它,你可以收集到目标系统的大量信息:
Hex-STRING: 00 50 56 FF 2A 8E
Hex-STRING: 00 0C 29 09 C3 79
Hex-STRING: 00 50 56 F0 EE E8
IpAddress: 172.16.36.2
IpAddress: 172.16.36.180
IpAddress: 172.16.36.254
在输出的一部分中,可以看到十六进制值和 IP 地址的列表。通过参考已知系统的网络接口,我们就可以知道,这些是 ARP 缓存的内容。它表明了储存在设备中的 IP 和 MAC 地址的关联。
STRING: "FreeSSHDService.exe"
STRING: "vmtoolsd.exe"
STRING: "java.exe"
STRING: "postgres.exe"
STRING: "java.exe"
STRING: "java.exe"
STRING: "TPAutoConnSvc.exe"
STRING: "snmp.exe"
STRING: "snmptrap.exe"
STRING: "TPAutoConnect.exe"
STRING: "alg.exe"
STRING: "cmd.exe"
STRING: "postgres.exe"
STRING: "freeSSHd 1.2.0"
STRING: "CesarFTP 0.99g"
STRING: "VMware Tools"
STRING: "Python 2.7.1"
STRING: "WebFldrs XP"
STRING: "VMware Tools"
此外,运行进程和安装的应用的列表可以在输出中找到。这个信息在枚举运行在目标系统的服务,以及识别潜在的可利用漏洞时十分有用。
工作原理
不像 Onesixtyone,SNMPwalk 不仅仅能够识别默认 SNMP 团体字符串的使用,也可以利用这个配置来收集大量来自目标系统的信息。这可以通过使用一序列 SNMP GETNEXT 请求,并使用请求来爆破系统的所有可用信息来完成。
4.14 Scapy 防火墙识别
通过评估从封包注入返回响应,我们就可以判断远程端口是否被防火墙设备过滤。为了对这个过程如何工作有个彻底的认识,我们可以使用 Scapy 在封包级别执行这个任务。
准备
为了使用 Scapy 来执行防火墙识别,你需要运行网络服务的远程系统。此外,你需要实现一些过滤机制。这可以使用独立防火墙设备,或者基于主机的过滤,例如 Windows 防火墙来完成。通过操作防火墙设备的过滤设置,你应该能够修改被注入封包的响应。
操作步骤
为了高效判断是否 TCP 端口被过滤,需要向目标端口发送 TCP SYN 和 ACK 封包。基于用于响应这些注入的封包,我们可以判断端口是否多虑。这两个封包的注入可能会产生四种不同的响应组合。我们会讨论每一种场景,它们对于目标端口的过滤来说表示什么,以及如何测试它们。这四个可能的响应组合如下:
- SYN 请求没有响应,ACK 请求收到 RST 响应。
- SYN 请求收到 SYN+ACK 或者 SYN+RST 响应,ACK 请求没有响应。
- SYN 请求收到 SYN+ACK 或者 SYN+RST 响应,ACK 请求收到 RST 响应。
- SYN 和 ACK 请求都没有响应。
SYN | ACK | |
---|---|---|
1 | 无响应 | RST |
2 | SYN + ACK/RST | 无响应 |
3 | SYN + ACK/RST | RST |
4 | 无响应 | 无响应 |
在第一种场景中,我们应该考虑 SYN 请求没有响应,ACK 请求收到 RST 响应的配置。为了测试它,我们首先应该发送 TCP ACK 封包给目标端口。为了发送 TCP ACK 封包给任何给定的端口,我们首先必须构建请求的层级,我们首先需要构建 IP 层:
root@KaliLinux:~# scapy Welcome to Scapy (2.2.0)
>>> i = IP()
>>> i.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= ip
chksum= None
src= 127.0.0.1
dst= 127.0.0.1
\options\
>>> i.dst = "172.16.36.135"
>>> i.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= ip
chksum= None
src= 172.16.36.180
dst= 172.16.36.135
\options\
为了构建请求的 IP 层,我们需要将IP
对象赋给变量i
。通过调用display
函数,我们可以确定对象的属性配置。通常,发送和接受地址都设为回送地址,127.0.0.1
。这些值可以通过修改目标地址来修改,也就是设置i.dst
为想要扫描的地址的字符串值。通过再次调用dislay
函数,我们看到不仅仅更新的目标地址,也自动更新了和默认接口相关的源 IP 地址。现在我们构建了请求的 IP 层,我们可以构建 TCP 层了。
>>> t = TCP()
>>> t.display()
###[ TCP ]###
sport= ftp_data
dport= http
seq= 0
ack= 0
dataofs= None
reserved= 0
flags= S
window= 8192
chksum= None
urgptr= 0
options= {}
>>> t.dport = 22
>>> t.flags = 'A'
>>> t.display()
###[ TCP ]###
sport= ftp_data
dport= ssh
seq= 0
ack= 0
dataofs= None
reserved= 0
flags= A
window= 8192
chksum= None
urgptr= 0
options= {}
为了构建请求的 TCP 层,我们使用和 IP 层相同的技巧。在这个立即中,TCP
对象赋给了t
变量。像之前提到的那样,默认的配置可以通过调用display
函数来确定。这里我们可以看到目标端口的默认值为 HTTP 端口 80。对于我们的首次扫描,我们将 TCP 设置保留默认。现在我们创建了 TCP 和 IP 层,我们需要将它们叠放来构造请求。
>>> request = (i/t)
>>> request.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= tcp
chksum= None
src= 172.16.36.180
dst= 172.16.36.135
\options\
###[ TCP ]###
sport= ftp_data
dport= ssh
seq= 0
ack= 0
dataofs= None
reserved= 0
flags= A
window= 8192
chksum= None
urgptr= 0
options= {}
我们可以通过以斜杠分离变量来叠放 IP 和 TCP 层。这些层面之后赋给了新的变量,它代表整个请求。我们之后可以调用dispaly
函数来查看请求的配置。一旦构建了请求,可以将其传递给sr1
函数来分析响应:
>>> response = sr1(request,timeout=1)
..Begin emission:
.........Finished to send 1 packets.
....*
Received 16 packets, got 1 answers, remaining 0 packets
>>> response.display()
###[ IP ]###
version= 4L
ihl= 5L
tos= 0x0
len= 40
id= 0
flags= DF
frag= 0L
ttl= 63
proto= tcp
chksum= 0x9974
src= 172.16.36.135
dst= 172.16.36.180
\options\
###[ TCP ]###
sport= ssh
dport= ftp_data
seq= 0
ack= 0
dataofs= 5L
reserved= 0L
flags= R
window= 0
chksum= 0xe5b
urgptr= 0
options= {}
###[ Padding ]###
load= '\x00\x00\x00\x00\x00\x00'
相同的请求可以不通过构建和堆叠每一层来执行。反之,我们使用单独的一条命令,通过直接调用函数并传递合适的参数:
>>> response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='A'),timeout=1)
..Begin emission:
........Finished to send 1 packets.
....*
Received 15 packets, got 1 answers, remaining 0 packets
>>> response
<IP version=4L ihl=5L tos=0x0 len=40 id=0 flags=DF frag=0L ttl=63 proto=tcp chksum=0x9974 src=172.16.36.135 dst=172.16.36.180 options=[] |<TCP sport=ssh dport=ftp_data seq=0 ack=0 dataofs=5L reserved=0L flags=R window=0 chksum=0xe5b urgptr=0 |<Padding load='\x00\x00\x00\x00\x00\x00' |>>>
要注意在这个特定场景中,注入的 ACK 封包的响应是 RST 封包。测试的下一步就是以相同方式注入 SYN 封包。
>>> response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='S'),timeout=1,verbose =1)
Begin emission:
Finished to send 1 packets.
Received 9 packets, got 0 answers, remaining 1 packets
以相同方式发送 SYN 请求之后,没有收到任何响应,并且函数在超时时间达到只有断开了连接。这个响应组合表明发生了状态包过滤。套接字通过丢掉 SYN 请求拒绝了所有入境的连接,但是没有过滤 ACK 封包来确保仍旧存在出境连接和持续中的通信。这个响应组合可以在 Python 中测试来确认状态过滤的端口:
root@KaliLinux:~# python
Python 2.7.3 (default, Jan 2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> ACK_response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='A'),timeout=1,verbose =0)
>>> SYN_response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='S'),timeout=1,verbose =0)
>>> if ((ACK_response == None) or (SYN_response == None)) and not ((ACK_response ==None) and (SYN_response == None)):
... print "Stateful filtering in place"
... Stateful filtering in place
>>> exit()
在使用 Scapy 生成每个请求之后,测试可以用于评估这些响应,来判断是否 ACK 或者 SYN(但不是全部)请求接受到了响应。这个测试对于识别该场景以及下一个场景十分高效,其中 SYN 注入而不是 ACK 注入接受到了响应。
SYN 注入收到了 SYN+ACK 或者 RST+ACK 响应,但是 ACK 注入没有收到响应的场景,也表明存在状态过滤。剩余的测试也一样。首先,向目标端口发送 ACK 封包。
>>> response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='A'),timeout=1,verbose =1)
Begin emission:
Finished to send 1 packets.
Received 16 packets, got 0 answers, remaining 1 packets
在这个场景中可以执行完全相同的测试,如果两哥注入请求之一收到响应,测试就表明存在状态过滤。
root@KaliLinux:~# python
Python 2.7.3 (default, Jan 2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> ACK_response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='A'),timeout=1,verbose =0)
>>> SYN_response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='S'),timeout=1,verbose =0)
>>> if ((ACK_response == None) or (SYN_response == None)) and not ((ACK_response ==None) and (SYN_response == None)):
... print "Stateful filtering in place"
... Stateful filtering in place
>>> exit()
响应的组合表明,状态过滤执行在 ACK 封包上,任何来自外部的符合上下文的 ACK 封包都会被丢弃。但是,入境连接尝试的响应表明,端口没有完全过滤。
另一个可能的场景就是 SYN 和 ACK 注入都收到了预期响应。这种情况下,没有任何形式的过滤。为了对这种情况执行测试,我们首先执行 ACK 注入,之后分析响应:
>>> response =
sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='A'),timeout=1,verbose=1)
Begin emission:
Finished to send 1 packets.
Received 5 packets, got 1 answers, remaining 0 packets
>>> response.display()
###[ IP ]###
version= 4L
ihl= 5L
tos= 0x0
len= 40
id= 0
flags= DF
frag= 0L
ttl= 64
proto= tcp
chksum= 0x9974
src= 172.16.36.135
dst= 172.16.36.180
\options\
###[ TCP ]###
sport= ssh
dport= ftp_data
seq= 0
ack= 0
dataofs= 5L
reserved= 0L
flags= R
window= 0
chksum= 0xe5b
urgptr= 0
options= {}
###[ Padding ]###
load= '\x00\x00\x00\x00\x00\x00'
在封包未被过滤的情况下,来路不明的 ACK 封包发送给了目标端口,并应该产生返回的 RST 封包。这个 RST 封包表明,ACK 封包不符合上下文,并且打算断开连接。发送了 ACK 注入之后,我们可以向相同端口发送 SYN 注入。
>>> response =
sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='S'),timeout=1,verbose =1)
Begin emission:
Finished to send 1 packets.
Received 4 packets, got 1 answers, remaining 0 packets
>>> response.display()
###[ IP ]###
version= 4L
ihl= 5L
tos= 0x0
len= 44
id= 0
flags= DF
frag= 0L
ttl= 64
proto= tcp
chksum= 0x9970
src= 172.16.36.135
dst= 172.16.36.180
\options\
###[ TCP ]###
sport= ssh
dport= ftp_data
seq= 1147718450
ack= 1
dataofs= 6L
reserved= 0L
flags= SA
window= 5840
chksum= 0xd024
urgptr= 0
options= [('MSS', 1460)]
###[ Padding ]###
load= '\x00\x00'
>>> response[TCP].flags
18L
>>> int(response[TCP].flags)
18
在端口未过滤并打开的情况中,会返回 SYN+ACK 响应。要注意 TCPflags
属性的实际值是个long
变量,值为 18。这个值可以轻易使用int
函数来转换成int
变量。这个 18 的值是 TCP 标识位序列的十进制值。SYN 标志的十进制值为 2,而 ACK 标识的十进制值为 16。假设这里没有状态过滤,我们可以通过评估 TCPflags
值的整数转换,在 Python 中测试端口是否未过滤并打开。
root@KaliLinux:~# python Python 2.7.3 (default, Jan 2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> ACK_response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='A'),timeout=1,verbose =0)
>>> SYN_response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='S'),timeout=1,verbose =0)
>>> if ((ACK_response == None) or (SYN_response == None)) and not ((ACK_response ==None) and (SYN_response == None)):
... print "Stateful filtering in place"
... elif int(SYN_response[TCP].flags) == 18:
... print "Port is unfiltered and open"
... elif int(SYN_response[TCP].flags) == 20:
... print "Port is unfiltered and closed"
... Port is unfiltered and open
>>> exit()
我们可以执行相似的测试来判断是否端口未过滤并关闭。未过滤的关闭端口会激活 RST 和 ACK 标识。像之前那样,ACK 标识为整数 16,RST 标识为 整数 4。所以,未过滤的关闭端口的 TCPflags
值的整数转换应该是 20:
root@KaliLinux:~# python Python 2.7.3 (default, Jan 2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> ACK_response = sr1(IP(dst="172.16.36.135")/TCP(dport=4444,flags='A'),timeout=1,verbo se=0)
>>> SYN_response = sr1(IP(dst="172.16.36.135")/TCP(dport=4444,flags='S'),timeout=1,verbo se=0)
>>> if ((ACK_response == None) or (SYN_response == None)) and not ((ACK_response ==None) and (SYN_response == None)):
... print "Stateful filtering in place"
... elif int(SYN_response[TCP].flags) == 18:
... print "Port is unfiltered and open"
... elif int(SYN_response[TCP].flags) == 20:
... print "Port is unfiltered and closed"
... Port is unfiltered and closed
>>> exit()
最后,我们应该考虑最后一种场景,其中 SYN 或者 ACK 注入都没有收到响应。这种场景中,每个sr1
的实例都会在超时的时候断开。
>>> response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='A'),timeout=1,verbose =1)
Begin emission:
Finished to send 1 packets.
Received 36 packets, got 0 answers, remaining 1 packets
>>> response = sr1(IP(dst="172.16.36.135")/TCP(dport=22,flags='S'),timeout=1,verbose =1)
Begin emission:
Finished to send 1 packets.
Received 18 packets, got 0 answers, remaining 1 packets
每个注入封包都缺少响应,表明端口存在无状态过滤,仅仅是丢弃所有入境的流量,无论状态是什么。或者这表明远程系统崩溃了。我们的第一想法可能是,可以通过在之前的测试序列的末尾向else
添加执行流,在 Python 中测试它。理论上,如果任何注入都没有接受到响应,else
中的操作会执行。简单来说,else
中的操作会在没有接收到响应的时候执行。
root@KaliLinux:~# python Python 2.7.3 (default, Jan 2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> ACK_response = sr1(IP(dst="172.16.36.135")/TCP(dport=4444,flags='A'),timeout=1,verbo se=0)
>>> SYN_response = sr1(IP(dst="172.16.36.135")/TCP(dport=4444,flags='S'),timeout=1,verbo se=0)
>>> if ((ACK_response == None) or (SYN_response == None)) and not ((ACK_response ==None) and (SYN_response == None)):
... print "Stateful filtering in place"
... elif int(SYN_response[TCP].flags) == 18:
... print "Port is unfiltered and open"
... elif int(SYN_response[TCP].flags) == 20:
... print "Port is unfiltered and closed"
... else:
... print "Port is either unstatefully filtered or host is down"
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: 'NoneType' object has no attribute '__getitem__'
这意味着理论上可以生效,但是实际上并不工作。操作值为空的变量的时候,Python 实际上会产生错误。为了避免这种问题,首先就需要检测没有收到任何回复的情况。
>>> if (ACK_response == None) and (SYN_response == None):
... print "Port is either unstatefully filtered or host is down"
... Port is either unstatefully filtered or host is down
这个完成的测试序列之后可以集成到单个功能性脚本中。这个脚本接受两个参数,包括目标 IP 地址和被测试的端口。之后注入 ACK 和 SYN 封包,如果存在响应,响应会储存用于评估。之后执行四个测试来判断是否端口上存在过滤。一开始,会执行测试来判断是否没有受到任何响应。如果是这样,输出会表示远程主机崩溃了,或者端口存在无状态过滤,并丢弃所有流量。如果接收到了任何请求,会执行测试来判断是否接受到了某个注入的响应,而不是全部。如果是这样,输出会表明端口存在状态过滤。最后如果两个注入都接受到了响应,端口会被识别为物过滤,并且会评估 TCP 标志位来判断端口开放还是关闭。
#!/usr/bin/python
import sys import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
if len(sys.argv) != 3:
print "Usage - ./ACK_FW_detect.py [Target-IP] [Target Port]"
print "Example - ./ACK_FW_detect.py 10.0.0.5 443"
print "Example will determine if filtering exists on port 443 of host 10.0.0.5"
sys.exit()
ip = sys.argv[1]
port = int(sys.argv[2])
ACK_response = sr1(IP(dst=ip)/TCP(dport=port,flags='A'),timeout=1,verbose=0)
SYN_response = sr1(IP(dst=ip)/TCP(dport=port,flags='S'),timeout=1,verbose=0)
if (ACK_response == None) and (SYN_response == None):
print "Port is either unstatefully filtered or host is down"
elif ((ACK_response == None) or (SYN_response == None)) and not ((ACK_response ==None) and (SYN_response == None)):
print "Stateful filtering in place"
elif int(SYN_response[TCP].flags) == 18:
print "Port is unfiltered and open"
elif int(SYN_response[TCP].flags) == 20:
print "Port is unfiltered and closed"
else:
print "Unable to determine if the port is filtered"
在本地文件系统创建脚本之后,需要更新文件许可来允许脚本执行。chmod
可以用于更新这些许可,脚本之后可以通过直接调用并传入预期参数来执行:
root@KaliLinux:~# chmod 777 ACK_FW_detect.py
root@KaliLinux:~# ./ACK_FW_detect.py
Usage - ./ACK_FW_detect.py [Target-IP] [Target Port]
Example - ./ACK_FW_detect.py 10.0.0.5 443
Example will determine if filtering exists on port 443 of host 10.0.0.5
root@KaliLinux:~# ./ACK_FW_detect.py 172.16.36.135 80 Port is unfiltered and open
root@KaliLinux:~# ./ACK_FW_detect.py 172.16.36.134 22 Host is either unstatefully filtered or is down
工作原理
SYN 和 ACK TCP 标志在有状态的网络通信中起到关键作用。SYN 请求允许建立新的 TCP 会话,而 ACK 响应用于在关闭之前维持会话。端口响应这些类型的封包之一,但是不响应另一种,就可能存在过滤,它基于会话状态来限制流量。通过识别这种情况,我们就能够推断出端口上存在状态过滤。
4.15 Nmap 防火墙识别
Nmap 拥有简化的防火墙过滤识别功能,基于 ACK 探测响应来识别端口上的过滤。这个功能可以用于测试单一端口或者多个端口序列来判断过滤状态。
准备
为了使用 Nmap 来执行防火墙识别,你需要运行网络服务的远程系统。此外,你需要实现一些过滤机制。这可以使用独立防火墙设备,或者基于主机的过滤,例如 Windows 防火墙来完成。通过操作防火墙设备的过滤设置,你应该能够修改被注入封包的响应。
操作步骤
为了使用 Nmap 执行防火墙 ACK 扫描,Nmap 应该以指定的 IP 地址,目标端口和-sA
选项调用。
root@KaliLinux:~# nmap -sA 172.16.36.135 -p 22
Starting Nmap 6.25 ( http://nmap.org ) at 2014-01-24 11:21 EST
Nmap scan report for 172.16.36.135
Host is up (0.00032s latency).
PORT STATE SERVICE
22/tcp unfiltered ssh
MAC Address: 00:0C:29:3D:84:32 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 0.05 seconds
root@KaliLinux:~# nmap -sA 83.166.169.228 -p 22
Starting Nmap 6.25 ( http://nmap.org ) at 2014-01-24 11:25 EST
Nmap scan report for packtpub.com (83.166.169.228)
Host is up (0.14s latency).
PORT STATE SERVICE
22/tcp filtered ssh
Nmap done: 1 IP address (1 host up) scanned in 2.23 seconds
通过在本地网络中的 Metasploitable2 系统上执行扫描,流量并不经过防火墙,响应表明 TCP 22 端口是未过滤的。但是,如果我对packtpub. com
的远程 IP 地址执行相同扫描,端口 22 是过滤器的。通过执行相同扫描,而不指定端口,端口过滤评估可以在 Nmap 的 1000 个常用端口上完成。
root@KaliLinux:~# nmap -sA 172.16.36.135
Starting Nmap 6.25 ( http://nmap.org ) at 2014-01-24 11:21 EST
Nmap scan report for 172.16.36.135
Host is up (0.00041s latency). All 1000 scanned ports on 172.16.36.135 are unfiltered
MAC Address: 00:0C:29:3D:84:32 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 0.10 seconds
对本地网络上的 Metasploit2 系统执行扫描时,由于它没有被任何防火墙保护,结果表明所有端口都是未过滤的。如果我们在packtpub.com
域内执行相同扫描,所有端口都识别为存在过滤,除了 TCP 端口 80,这是 Web 应用部署的地方。要注意在扫描端口范围的时候,输出只包含未过滤的端口。
root@KaliLinux:~# nmap -sA 83.166.169.228
Starting Nmap 6.25 ( http://nmap.org ) at 2014-01-24 11:25 EST
Nmap scan report for packtpub.com (83.166.169.228)
Host is up (0.15s latency).
Not shown: 999 filtered ports
PORT STATE SERVICE
80/tcp unfiltered http
Nmap done: 1 IP address (1 host up) scanned in 13.02 seconds
为了在所有可能的 TCP 端口上执行扫描,需要奥妙所有可能的端口地址。定义了来源和目标端口地址的 TCP 头部部分是 16 位长,每一位可以为值 1 或者 0。所以一共有2 **16
或 65536 个 TCP 端口地址。为了扫描所有可能的地址空间,必须提供 1 到 65535 的 范围。
root@KaliLinux:~# nmap -sA 172.16.36.135 -p 1-65535
Starting Nmap 6.25 ( http://nmap.org ) at 2014-01-24 11:21 EST
Nmap scan report for 172.16.36.135
Host is up (0.00041s latency).
All 65535 scanned ports on 172.16.36.135 are unfiltered
MAC Address: 00:0C:29:3D:84:32 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 1.77 seconds
工作原理
除了 Nmap 提供的许多功能,它也可以用于识别防火墙过滤。这意味着 Nmap 通过使用之前在 Scapy 秘籍中讨论的相同技巧,来执行这种防火墙识别。SYN 和 来路不明的 ACK 的组合会发送给目标端口,响应用于分析来判断过滤状态。
4.18 Metasploit 防火墙识别
Metasploit 拥有一个扫描辅助模块,可以用于指定多线程网络端口分析,基于 SYN/ACK 探测响应分析,来判断端口是否被过滤。
准备
为了使用 Metasploit 来执行防火墙识别,你需要运行网络服务的远程系统。此外,你需要实现一些过滤机制。这可以使用独立防火墙设备,或者基于主机的过滤,例如 Windows 防火墙来完成。通过操作防火墙设备的过滤设置,你应该能够修改被注入封包的响应。
操作步骤
为了使用 Metasploit ACK 扫描模块来执行防火墙和过滤识别,你首先必须从 Kali 的终端中启动 MSF 控制台,之后使用use
命令选项所需的辅助模块。
root@KaliLinux:~# msfconsole
# cowsay++
____________
< metasploit >
-----------
\ ,__,
\ (oo)____
(__) )\
||--|| *
Using notepad to track pentests? Have Metasploit Pro report on hosts, services, sessions and evidence -- type 'go_pro' to launch it now.
=[ metasploit v4.6.0-dev [core:4.6 api:1.0]
+ -- --=[ 1053 exploits - 590 auxiliary - 174 post
+ -- --=[ 275 payloads - 28 encoders - 8 nops
msf > use auxiliary/scanner/portscan/ack
msf auxiliary(ack) > show options
Module options (auxiliary/scanner/portscan/ack):
Name Current Setting Required Description
---- --------------- -------- ----------
BATCHSIZE 256 yes The number of hosts to scan per set
INTERFACE no The name of the interface
PORTS 1-10000 yes Ports to scan (e.g. 22- 25,80,110-900)
RHOSTS yes The target address range or CIDR identifier
SNAPLEN 65535 yes The number of bytes to capture
THREADS 1 yes The number of concurrent threads
TIMEOUT 500 yes The reply read timeout in milliseconds
一旦选择了模块,可以使用show options
命令来确认或更改扫描配置。这个命令会展示四个列的表格,包括name
、current settings
、required
和description
。name
列标出了每个可配置变量的名称。current settings
列列出了任何给定变量的现有配置。required
列标出对于任何给定变量,值是否是必须的。description
列描述了每个变量的功能。任何给定变量的值可以使用set
命令,并且将新的值作为参数来修改。
msf auxiliary(ack) > set PORTS 1-100
PORTS => 1-100
msf auxiliary(ack) > set RHOSTS 172.16.36.135
RHOSTS => 172.16.36.135
msf auxiliary(ack) > set THREADS 25
THREADS => 25
msf auxiliary(ack) > show options
Module options (auxiliary/scanner/portscan/ack):
Name Current Setting Required Description
---- --------------- -------- ----------
BATCHSIZE 256 yes The number of hosts to scan per set
INTERFACE no The name of the interface
PORTS 1-100 yes Ports to scan (e.g. 22- 25,80,110-900)
RHOSTS 172.16.36.135 yes The target address range or CIDR identifier
SNAPLEN 65535 yes The number of bytes to capture
THREADS 25 yes The number of concurrent threads
TIMEOUT 500 yes The reply read timeout in milliseconds
在上面的例子中,RHOSTS
值修改为我们打算扫描的远程系统的 IP 地址。此外,线程数量修改为 20。THREADS
的值定义了在后台执行的当前任务数量。确定线程数量涉及到寻找一个平衡,既能提升任务速度,又不会过度消耗系统资源。对于多数系统,20 个线程可以足够快,并且相当合理。修改了必要的变量之后,可以再次使用show options
命令来验证。一旦所需配置验证完毕,就可以执行扫描了。
msf auxiliary(ack) > run
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
这个例子中,唯一提供的输出就是有关扫描的源信息,它显示了被扫描系统的数量,以及模块执行完毕。输出的缺乏是因为,和 SYN 以及 ACK 注入相关的响应从一个端口直接到达另一个端口,因为 Metasploitable2 系统没有任何防火墙。作为替代,如果我们在packtpub.com
域上执行相同扫描,通过将RHOSTS
值修改为和它相关的 IP 地址,我们会收到不用的输出。因为这个主机放在防火墙背后,和未过滤端口相关的响应中的变化如下:
msf auxiliary(ack) > set RHOSTS 83.166.169.228
RHOSTS => 83.166.169.228
msf auxiliary(ack) > show options
Module options (auxiliary/scanner/portscan/ack):
Name Current Setting Required Description
---- --------------- -------- ----------
BATCHSIZE 256 yes The number of hosts to scan per set
INTERFACE no The name of the interface
PORTS 1-100 yes Ports to scan (e.g. 22- 25,80,110-900)
RHOSTS 83.166.169.228 yes The target address range or CIDR identifier
SNAPLEN 65535 yes The number of bytes to capture
THREADS 25 yes The number of concurrent threads
TIMEOUT 500 yes The reply read timeout in milliseconds
msf auxiliary(ack) > run
[*] TCP UNFILTERED 83.166.169.228:80
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
工作原理
Metasploit 拥有一个辅助模块,可以以多种技巧执行防火墙识别,这些技巧之前讨论过。但是,Metasploit 也提供了一些功能来分析防火墙上下文,可以用于其它信息的收集甚至是利用。