侦察是每个bug bounty或渗透测试中最为重要的阶段之一。侦察工作做得到不到位,可能会对最终的结果产生直接影响。侦察可以分为两类:即主动和被动侦察。在主动侦察中端口扫描是最常用的方法之一。通过端口扫描渗透测试人员或漏洞猎人可以确定在目标主机或网络上打开的端口,以及识别在这些端口上运行的服务。
然而,有个问题就是如何在网络端口扫描期间寻找速度和准确度之间的平衡点?在渗透测试期间,他们的时间非常有限,往往需要在规定的时间内完成测试任务;而在bug bounty中,总会有人和你抢着发现并提交bug。这些原因也迫使我们在端口扫描期间优先考虑其速度而非准确性。这样做的缺点也显而易见,那就是不准确。并可能因此让我们错过某些重要的端口,并导致最终结果的改写。
这项研究的目的旨在使用开源和知名工具进行网络端口扫描时,找到速度和精准度之间的平衡点。
端口扫描是侦察阶段最常用的技术之一。通过扫描渗透测试人员或漏洞猎人可以快速识别主机上可用的开放端口,以及在这些开放端口上运行的服务。
端口扫描器可以根据其工作方式进行分类:面向连接(同步模式)和无连接(异步模式)扫描器。
这种类型的扫描器会向目标端口发送一个请求并等待其响应,直至到达超时时间为止。这种类型的扫描器的缺点是其性能较慢,因为扫描器在当前连接关闭之前不会进入下一个目标端口或IP。
面向连接的扫描器的好处在于具有较高的准确性,因为它们可以识别丢弃的数据包。
面向连接的扫描器最典型的例子就是Nmap。
无连接扫描器不依赖于当前被探测端口的完成来启动下一个端口,因为它们具有单独的发送和接收线程。这允许他们进行高速的扫描。但这些扫描器的缺点就是不太准确,因为它们无法检测丢弃的数据包。
Masscan和Zmap是两款最流行的无连接扫描器。
这项研究只包括Nmap和Masscan。虽然Zmap产生了良好的结果且速度也非常的快,但它一次只能扫描一个端口。根据经验,即使多个作业同时运行,Zmap扫描仍然很慢。
尽管Nmap和Masscan都拥有良好的性能,功能和结果,但它们仍有其自身的弱点。下表显示了这两种工具的优点和缺点。
Nmap
两者之间更准确(使用同步模式)
有较多功能
接受域名和IP地址(IPv4和IPv6)
Masscan
非常快(使用异步模式)
语法与Nmap非常相似
Nmap
扫描数量较大的目标时速度很慢
Masscan
高速率的扫描较大端口范围时结果不太准确
不接受域名作为目标输入
不会根据环境自动调整传输速率
基于上述工具的优缺点,在试图找到速度和准确度之间的平衡时,我大致确定了以下解决方案和问题。
以下是基于PROS的解决方案:
1.将Nmap的准确性及其功能与Masscan的速度相结合。
2.使用Masscan执行初始端口扫描,以识别打开的端口和具有打开端口的主机。
3.使用Masscan的结果(已识别的开放端口和主机)作为Nmap的输入以进行详细的端口扫描。
虽然上面列出的想法很好,但我们仍然需要解决每个工具存在的缺点。具体来说,我们需要解决:
1.Nmap在扫描数量较大的目标时性能缓慢。
2.Masscan在高速率的扫描较大端口范围时结果不太准确[2]。
我选择了以下子网作为本研究的目标网络:
Targets | Subnets |
---|---|
A | A.A.0.0/16 |
B | B.B.0.0/16 |
C | C.C.0.0/16 |
D | D.D.0.0/16 |
由于预算有限,研究期间我仅使用了一台机器作为扫描机器。我使用的扫描机器是DigitalOcean 20美元的VPS,具有4GB RAM,2个vCPU和4TB的月带宽。在整个研究过程中,该机器仅使用了1个位于固定位置的IP地址。
对于这项研究,两种工具都有自己的测试用例,这些测试用例是每种工具中可用的不同选项的变体。这些测试用例旨在解决工具存在的缺点,并利用它们的优点来找到速度和准确性之间的平衡点。
1.以不同速率常规扫描所有TCP端口。
2.将/16目标子网拆分为/20块,并运行X个并发Masscan作业,每个作业的速率为Y。
3.将1-65535端口范围拆分为多个范围,并运行X个并发Masscan作业,每个作业的速率为Y。
1.常规扫描所有TCP端口。
2.使用X个并发作业扫描所有TCP端口。
3.扫描Masscan识别的开放端口和主机的组合列表。
4.扫描Masscan识别的特定主机上的特定开放端口。
在有限的时间内,不可能涵盖选项的每一个变化/组合,因此仅涵盖上述内容。
对于使用并发作业的测试用例,使用了GNU Parallel。如果你是这个工具的新手,请查看此处的详细教程。
研究所使用的相关版本为:Nmap v7.70和Masscan v1.0.5-51-g6c15edc。
该研究仅涉及IPv4地址。
不包括扫描UDP端口。
只使用了最流行的开源工具。(Zmap未包括在内,因为它一次只扫描一个端口;即使运行多个作业,扫描速度也非常的慢。)
只探测了4个目标网络,它们都为/16。
端口扫描仅来自一台机器,其中一个IP地址位于固定位置。
由于扫描机器不支持PF_RING,因此Masscan速率限制为250kpps。
并非所有测试用例组合都是由于资源有限而进行的(这样做非常耗时)。
以下部分将详细介绍使用Masscan执行的不同测试用例及其结果。
这个测试用例没有什么特别之处。只是使用Masscan的正常扫描,但速率不同。
以下命令用于启动此测试用例的扫描:
masscan -p 1-65535 --rate RATE--wait 0 --open TARGET_SUBNET -oG TARGET_SUBNET.gnmap
使用速率:
1M
100K
50K
在实验过程中,我的VPS可以运行的最大速率仅为250kpps左右。这是因为扫描机不支持PF_RING的原因。
图表:
观察:
较慢的速率会发现更多的开放端口,但代价是扫描会花费更多的时间。
为了能够运行并发作业,我决定将/16目标子网拆分为更小的子网。你可以将它们拆分为其他较小的子网,例如/24,而对于本研究我将其拆分为了/20。
要将目标网络拆分为较小的子网,可以使用以下python代码:
#!/usr/bin/python3
import ipaddress, sys
target = sys.argv[1]
prefix = int(sys.argv[2])
for subnet in ipaddress.ip_network(target).subnets(new_prefix=prefix):
print(subnet)
运行结果如下:
每项工作所用的速率都是基于扫描机能够处理的最大化速率。在我的例子中,我的扫描机只能处理250kps,所以如果我要运行5个并发作业,每个作业都可以使用50kps的速率。
由于机器的最大速率不是“绝对的”(在这种情况下不完全是250kpps),你可以设置每个作业的速率,使总速率等于最大速率的80-90%。
对于这个测试用例,执行了下面的命令。split.py输出的较小子网被parallel用作运行并发作业的输入。
python3 split.py TARGET_SUBNET 20 | parallel -j JOBS "masscan -p 1-65535 --rate RATE--wait 0 --open {} -oG {//}.gnmap"
上述命令执行如下。在这种情况下,20个Masscan作业同时运行,每个作业的速率为10Kpps。
使用速率和作业:
5 jobs each w/ 100k rate
5 jobs each w/ 50k rate
20 jobs each w/ 10k rate
注意:
我错误计算了第一个速率和作业的差异(5 jobs each w/ 100k rate),因为它的总速率为500kpps,而我的机器只能处理250kpps。尽管如此,结果仍然是有价值的,正如你将在以下图表中看到的。
其他组合,例如10 jobs each w/ 20k rate是可行的,但由于时间和预算有限,我无法涵盖所有可能的组合。
图表:
观察:
运行concurrents作业的速度比常规扫描(测试用例#1)快2-3倍,但结果导致扫描较少的开放端口。
使用扫描机的最大速率容量将导致扫描较少的开放端口(5 jobs each w/ 100k rate)。
较少的作业使用高速率(5 jobs each w/ 50k rate),比较多作业使用低速率(20 jobs each w/ 10k rate)要好。
第3个测试用例尝试解决Masscan在扫描大端口范围时的问题,尤其是针对整个1-65535端口范围的扫描。我的解决方案是将1-65535端口范围,拆分为多个小范围。
就像之前的测试用例一样,设置每个作业的速率,使总速率等于最大速率的80-90%。
以下命令用于此测试用例。PORT_RANGES包含端口范围列表,它们被作为parallel输入使用用于并发任务。
cat PORT_RANGES | parallel -j JOBS "masscan -p {} --rate RATE --wait 0 --open TARGET_SUBNET -oG {}.gnmap"
1-65535端口范围的拆分有4种方式,如下所示,每个拆分包含作业和速率的组合/变化。
第一种拆分方式:5组端口范围
1-13107
13108-26214
26215-39321
39322-52428
52429-65535
使用速率和作业:
5 jobs each w/ 50k rate
2 jobs each w/ 100k rate
图表:
第二种拆分方式:2组端口范围
1-32767
32768-65535
使用速率和作业:
2 jobs each w/ 100k rate
2 jobs each w/ 125k rate
图表:
第三种拆分方式:8组端口范围
1-8190
8191-16382
16383-24574
24575-32766
32767-40958
40959-49151
49152-57343
57344-65535
使用速率和作业:
4 jobs each w/ 50k rate
2 jobs each w/ 100k rate
图表:
第四种拆分方式:4组端口范围
1-16383
16384-32767
32768-49151
49152-65535
使用速率和作业:
2 jobs each w/ 100k rate
我之所以这么做,是因为我意识到了我已经超出了每月的带宽限制。为此,我不得不多付了100美元。
图表:
观察:
以下列出的观察结果涵盖了上面提到的所有4个部分。
拆分端口范围会导致更多开放端口(这解决Masscan的问题)。
使用较少的并行作业(本例中为2个作业)会导致更多的开放端口。
在测试中5组端口范围的拆分方式结果最佳。
下表显示了使用上述不同Masscan测试用例进行实验的原始数据。
根据Masscan测试用例的结果,得出以下结论:
以100%的CPU利用率运行扫描机会导致扫描较少的开放端口。
使用机器的最大速率容量会导致扫描较少的开放端口。
当使用parallel任务时,较少的作业会导致扫描更多的开放端口。
拆分端口范围比拆分目标子网要好。
4到5组的端口拆分方式,产生的结果最佳。
此阶段只执行版本扫描,不包括使用Nmap的NSEs、OS guess及其他扫描功能。Nmap的线程被限制为T4相当于:
--max-rtt-timeout=1250ms --min-rtt-timeout=100ms --initial-rtt-timeout=500ms --max-retries=6 --max-scan-delay=10ms
以下Nmap选项也用于模拟Masscan使用的选项。这些选项适用于所有Nmap测试用例。
使用的选项:
SYN scan (-sS)
Version scan (-sV)
Threads (-T4)
Randomize target hosts order (--randomize-hosts)
No ping (-Pn)
No DNS resolution (-n)
该测试用例只是使用Nmap进行常规的扫描,因此并没有什么特别之处。
此测试用例的命令为:
sudo nmap -sSV -p- -v --open -Pn -n --randomize-hosts -T4 TARGET_SUBNET -oA OUTPUT
观察:
扫描4.5天后,作业仍未完成。这是之前提到的缺点之一;当扫描大型目标网络时,Nmap非常的慢。
由于性能非常低,我决定取消这个测试用例。
在本例中,我试图通过运行并发的Nmap扫描来解决Nmap的低性能问题。这是通过将目标子网拆分成更小的块来完成的,就像我之前对Masscan所做的那样。同样,使用下面的python代码split.py来分割目标子网。
#!/usr/bin/python3
import ipaddress, sys
target = sys.argv[1]
prefix = int(sys.argv[2])
for subnet in ipaddress.ip_network(target).subnets(new_prefix=prefix):
print(subnet)
此测试用例的命令如下:
python3 split.py TARGET_SUBNET 20 | parallel -j JOBS "sudo nmap -sSV -p- -v --open -Pn -n --randomize-hosts -T4 {} -oA {//}"
对于该测试用例,我决定运行两个并行作业实例,可以在下面找到。
使用5个并发作业:/16个目标子网拆分为/20个子网
观察:
同样非常的慢。2.8天后扫描仍未完成,所以我取消了扫描。
使用64个并发作业:/16目标子网拆分为/24个子网
观察:
五天过去了,扫描仍未完成,所以我也取消了它。
这个测试用例的思路是,首先获取主机列表和Masscan检测到的开放端口组合列表。这个开放端口的组合列表被用作基线(在下面的图表中显示为绿条),以确定下面的Nmap测试用例是否可以检测到更多或较少的开放端口。
例如,Masscan检测到300个开放端口,而常规Nmap扫描检测到320个开放端口。但当使用5个并发的Nmap扫描时,仅检测到了295个开放端口。这意味着常规Nmap扫描会是更好的选择。
使用以下命令从Masscan的输出中获取主机列表:
grep "Host:" MASSCAN_OUTPUT.gnmap | cut -d " " -f2 | sort -V | uniq > HOSTS
下图显示了上述命令的运行情况。
以下命令用于获取Masscan检测到的所有开放端口的组合列表。
grep "Ports:" MASSCAN_OUTPUT.gnmap | cut -d " " -f4 | cut -d "/" -f1 | sort -n | uniq | paste -sd, > OPEN_PORTS
下图显示了命令的运行情况。
以下命令用于运行常规的Nmap扫描。
sudo nmap -sSV -p OPEN_PORTS -v --open -Pn -n --randomize-hosts -T4 -iL HOSTS -oA OUTPUT
而下面的命令则用于运行并发的Nmap扫描。这将使用上面命令生成的主机列表和开放端口的组合列表。
cat HOSTS | parallel -j JOBS "sudo nmap -sSV -p OPEN_PORTS -v --open -Pn -n --randomize-hosts -T4 {} -oA {}"
使用的作业:
0 (这是常规的Nmap扫描)
10
50
100
图表:
观察:
运行常规Nmap扫描时,CPU利用率仅为10%左右。
常规Nmap扫描发现了更多的开放端口,而并发Nmap扫描则发现的开放端口较少。
与基线(图表上的绿条)相比,在某些目标网络(子网A)上识别出更多的开放端口,而在其他目标网络(子网B和C)上检测到的开放端口较少,并且在某些网络( 子网D)上没有太大差异。
Nmap检测到的其他开放端口
先看下面的表格。例如,假设Masscan在每台主机上都检测到了以下的开放端口(第2列)。在运行Nmap扫描时,Masscan检测到的所有开放端口的组合将用作目标端口(第3列)。
在我们的示例中,Nmap在完成扫描后检测到新的开放端口(第4列中的粗体文本)。这是如何发生的?Masscan是一个异步扫描器,它可能错过了主机192.168.1.2和192.168.1.3上的22端口。由于我们合并了每个主机上所有检测到的开放端口,并将它们用作Nmap的目标端口,因此将再次探测错过的端口(22)。需要注意的是,无法保证Nmap能够将其检测为开放状态,因为还有其他可能影响扫描的因素。
主机 | 通过Masscan检测到的开放端口 | Nmap扫描期间的目标端口 | 运行Nmap后检测到的开放端口 |
---|---|---|---|
192.168.1.1 | 22,80,443 | 22,80,443,8080,8888 | 22,80,443 |
192.168.1.2 | 8080,8888 | 22,80,443,8080,8888 | 22,8080,888 |
192.168.1.3 | 80,443 | 22,80,443,8080,8888 | 22,80,443 |
这一个与前一个测试用例有点相似。在这里,我没有合并Masscan从每个主机检测到的所有打开的端口。无论Masscan在特定主机上检测到哪些开放端口,Nmap都将使用相同的端口。下表说明了为此测试用例执行的操作。
主机 | 通过Masscan检测到的开放端口 | Nmap扫描期间的目标端口 |
---|---|---|
192.168.1.1 | 22,80,443 | 22,80,443 |
192.168.1.2 | 8080,8888 | 8080,8888 |
192.168.1.3 | 80,443 | 80,443 |
以下命令用于获取主机列表。
cat MASSCAN_OUTPUT.gnmap | grep Host | awk '{print $2,$5}' | sed 's@/.*@@' | sort -t' ' -n -k2 | awk -F' ' -v OFS=' ' '{x=$1;$1="";a[x]=a[x]","$0}END{for(x in a) print x,a[x]}' | sed 's/, /,/g' | sed 's/ ,/ /' | sort -V -k1 | cut -d " " -f1 > HOSTS
下图显示了命令的运行情况。
执行以下命令从各个主机获取开放端口的列表。
cat MASSCAN_OUTPUT.gnmap | grep Host | awk '{print $2,$5}' | sed 's@/.*@@' | sort -t' ' -n -k2 | awk -F' ' -v OFS=' ' '{x=$1;$1="";a[x]=a[x]","$0}END{for(x in a) print x,a[x]}' | sed 's/, /,/g' | sed 's/ ,/ /' | sort -V -k1 | cut -d " " -f2 > OPEN_PORTS
下图显示了命令的运行情况。
可以看到,输出不同于测试用例3中使用的命令。我们没有组合所有开放的端口,而是创建了从各个主机找到的所有开放端口的列表。
然后,这两个列表被用作输入到parallel,使用::::选项,以同时运行Nmap扫描。
同样,如果你对GNU Parallel并不熟悉,可以查看此处的教程。
parallel -j JOBS --link "sudo nmap -sSV -p {2} -v --open -Pn -n -T4 {1} -oA {1}" :::: HOSTS :::: OPEN_PORTS
这是一个基于以上两图,当上述parallel命令被执行启动同步扫描时会发生的情况的示例。
sudo nmap -sSV -p 443 -v --open -Pn -n -T4 192.168.1.2 -oA 192.168.1.2
sudo nmap -sSV -p 80,443,1935,9443 -v --open -Pn -n -T4 192.168.1.5 -oA 192.168.1.5
sudo nmap -sSV -p 80 -v --open -Pn -n -T4 192.168.1.6 -oA 192.168.1.6
sudo nmap -sSV -p 80,443 -v --open -Pn -n -T4 192.168.1.7 -oA 192.168.1.7
sudo nmap -sSV -p 08,443 -v --open -Pn -n -T4 192.168.1.9 -oA 192.168.1.9
下图显示了执行测试用例时所发生的情况的一个片段。如下所示,10个并发的Nmap扫描正在使用parallel运行。
使用的作业:
10
50
100
图表:
观察:
更多的并发作业和以100%的CPU利用率运行机器会导致较少的开放端口检测。
10到50个并发的Nmap扫描没有太大的区别,所以建议运行50个并发作业来缩短扫描时间。
此测试用例略快于测试用例3,但检测到的开放端口较少。
下表显示了使用上述不同Nmap测试用例进行实验的原始数据。
根据Nmap测试用例的结果,得出以下结论:
使用Masscan(测试用例#3)识别的组合开放端口运行Nmap扫描可获得最佳结果。这也是推荐的方法,因为有可能发现额外的开放端口。
以100%的CPU利用率运行扫描机会导致扫描较少的开放端口。
使用parallel任务时,较少的作业会导致扫描更多的开放端口。
根据对Masscan和Nmap进行的测试用例的结果,建议在网络范围的端口扫描期间采用以下方法实现速度与准确度之间的平衡:
1.首先运行2个或3个并发Masscan作业,所有65535个端口分为4-5组范围。
2.从Masscan的输出中获取主机列表和开放端口组合列表。
3.使用这些列表作为Nmap的输入并执行常规Nmap扫描。
对于这两种工具,应避免以下行为导致的较少开放端口检测:
扫描时应避免CPU过载。
不要使用扫描机的最大速率容量。
避免运行太多的并发任务。
虽然这项研究提供了一种如何在网络端口扫描期间寻找速度和准确度平衡的方法,但大家不应将此视为100%可靠。由于我个人的时间和预算有限,研究期间排除了诸多因素。最值得注意的是,在整个研究期间我仅使用了一个IP地址,显然这并不是一个严谨的设置。由于我对相同的目标网络执行了多次扫描,因此扫描机的IP地址可能会以某种形式被列入黑名单,这可能会对开放端口的检测数量带来影响。
https://capt-meelo.github.io//pentest/2019/01/16/offsec-certs.html
https://capt-meelo.github.io//pentest/2018/08/03/pwning-with-telerik.html
https://capt-meelo.github.io//pentest/2018/06/26/patching-doublepulsar.html
* 参考来源:secist,FB小编secist编译,转载请注明来自FreeBuf.COM
精彩推荐