在網絡端口掃描期間尋找速度和準確度之間的平衡點
介紹
偵察是每個bug bounty或滲透測試中最爲重要的階段之一。偵察工作做得到不到位,可能會對最終的結果產生直接影響。偵察可以分爲兩類:即主動和被動偵察。在主動偵察中端口掃描是最常用的方法之一。通過端口掃描滲透測試人員或漏洞獵人可以確定在目標主機或網絡上打開的端口,以及識別在這些端口上運行的服務。
然而,有個問題就是如何在網絡端口掃描期間尋找速度和準確度之間的平衡點?在滲透測試期間,他們的時間非常有限,往往需要在規定的時間內完成測試任務;而在bug bounty中,總會有人和你搶着發現並提交bug。這些原因也迫使我們在端口掃描期間優先考慮其速度而非準確性。這樣做的缺點也顯而易見,那就是不準確。並可能因此讓我們錯過某些重要的端口,並導致最終結果的改寫。
這項研究的目的旨在使用開源和知名工具進行網絡端口掃描時,找到速度和精準度之間的平衡點。
端口掃描概述
端口掃描是偵察階段最常用的技術之一。通過掃描滲透測試人員或漏洞獵人可以快速識別主機上可用的開放端口,以及在這些開放端口上運行的服務。
端口掃描器可以根據其工作方式進行分類:面向連接(同步模式)和無連接(異步模式)掃描器。
面向連接(同步模式)
這種類型的掃描器會向目標端口發送一個請求並等待其響應,直至到達超時時間爲止。這種類型的掃描器的缺點是其性能較慢,因爲掃描器在當前連接關閉之前不會進入下一個目標端口或IP。
面向連接的掃描器的好處在於具有較高的準確性,因爲它們可以識別丟棄的數據包。
面向連接的掃描器最典型的例子就是 Nmap 。
無連接(異步模式)
無連接掃描器不依賴於當前被探測端口的完成來啓動下一個端口,因爲它們具有單獨的發送和接收線程。這允許他們進行高速的掃描。但這些掃描器的缺點就是不太準確,因爲它們無法檢測丟棄的數據包。
Nmap vs Masscan
這項研究只包括Nmap和Masscan。雖然Zmap產生了良好的結果且速度也非常的快,但它一次只能掃描一個端口。根據經驗,即使多個作業同時運行,Zmap掃描仍然很慢。
儘管Nmap和Masscan都擁有良好的性能,功能和結果,但它們仍有其自身的弱點。下表顯示了這兩種工具的優點和缺點。
Nmap | Masscan | |
---|---|---|
優點 | – 兩者之間更準確(使用同步模式) - 有較多功能 - 接受域名和IP地址(IPv4和IPv6) |
– 非常快(使用異步模式) – 語法與Nmap非常相似 |
缺點 | – 掃描數量較大的目標時速度很慢 | - 高速率的掃描較大端口範圍時結果不太準確 [1] - 不接受域名作爲目標輸入 - 不會根據環境自動調整傳輸速率 |
研究思路
基於上述工具的優缺點,在試圖找到速度和準確度之間的平衡時,我大致確定了以下解決方案和問題。
解決方案
以下是基於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地址。
測試用例
對於這項研究,兩種工具都有自己的測試用例,這些測試用例是每種工具中可用的不同選項的變體。這些測試用例旨在解決工具存在的缺點,並利用它們的優點來找到速度和準確性之間的平衡點。
Masscan:
1.以不同速率常規掃描所有TCP端口。 2.將/16目標子網拆分爲/20塊,並運行X個併發Masscan作業,每個作業的速率爲Y。 3.將1-65535端口範圍拆分爲多個範圍,並運行X個併發Masscan作業,每個作業的速率爲Y。
Nmap:
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執行的不同測試用例及其結果。
測試用例#1:使用不同的速率常規掃描所有的TCP端口
這個測試用例沒有什麼特別之處。只是使用Masscan的正常掃描,但速率不同。
以下命令用於啓動此測試用例的掃描:
masscan -p 1-65535 --rate RATE--wait 0 --open TARGET_SUBNET -oG TARGET_SUBNET.gnmap
使用速率:
1M 100K 50K
在實驗過程中,我的VPS可以運行的最大速率僅爲250kpps左右。這是因爲掃描機不支持PF_RING的原因。
圖表:
觀察:
較慢的速率會發現更多的開放端口,但代價是掃描會花費更多的時間。
測試用例#2:將/16目標子網拆分爲/20塊,並運行X個併發Masscan作業,每個作業的速率爲Y
爲了能夠運行併發作業,我決定將/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:將1-65535端口範圍拆分爲多個小範圍,並運行x個併發Masscan作業,每個作業的速率爲Y
第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 結論
根據Masscan測試用例的結果,得出以下結論:
以100%的CPU利用率運行掃描機會導致掃描較少的開放端口。
使用機器的最大速率容量會導致掃描較少的開放端口。
當使用parallel任務時,較少的作業會導致掃描更多的開放端口。
拆分端口範圍比拆分目標子網要好。
4到5組的端口拆分方式,產生的結果最佳。
Nmap 測試用例和結果
此階段只執行版本掃描,不包括使用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)
測試用例#1:常規掃描所有TCP端口
該測試用例只是使用Nmap進行常規的掃描,因此並沒有什麼特別之處。
此測試用例的命令爲:
sudo nmap -sSV -p- -v --open -Pn -n --randomize-hosts -T4 TARGET_SUBNET -oA OUTPUT
觀察:
掃描4.5天后,作業仍未完成。這是之前提到的缺點之一;當掃描大型目標網絡時,Nmap非常的慢。
由於性能非常低,我決定取消這個測試用例。
測試用例#2:使用X個併發作業掃描所有TCP端口
在本例中,我試圖通過運行併發的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個子網
觀察:
五天過去了,掃描仍未完成,所以我也取消了它。
測試用例#3:掃描Masscan識別的開放端口和主機的組合列表
這個測試用例的思路是,首先獲取主機列表和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 |
測試用例#4:掃描Masscan識別的特定主機上的特定開放端口
這一個與前一個測試用例有點相似。在這裏,我沒有合併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運行。
使用的作業:
圖表:
觀察:
更多的併發作業和以100%的CPU利用率運行機器會導致較少的開放端口檢測。
10到50個併發的Nmap掃描沒有太大的區別,所以建議運行50個併發作業來縮短掃描時間。
此測試用例略快於測試用例3,但檢測到的開放端口較少。
原始數據
下表顯示了使用上述不同Nmap測試用例進行實驗的原始數據。
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地址可能會以某種形式被列入黑名單,這可能會對開放端口的檢測數量帶來影響。