第四章 指纹识别(三)

作者:Justin Hutchens

译者:飞龙

协议:CC BY-NC-SA 4.0

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 请求都没有响应。
SYNACK
1无响应RST
2SYN + ACK/RST无响应
3SYN + ACK/RSTRST
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命令来确认或更改扫描配置。这个命令会展示四个列的表格,包括namecurrent settingsrequireddescriptionname列标出了每个可配置变量的名称。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 也提供了一些功能来分析防火墙上下文,可以用于其它信息的收集甚至是利用。

GitHub 加速计划 / li / linux-dash
6
1
下载
A beautiful web dashboard for Linux
最近提交(Master分支:3 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐