本篇為翻譯文
編輯於:2019-08-17
首發:https://xz.aliyun.com/t/6001
原文:https://captmeelo.com/pentest/2019/07/29/port-scanning.html
最近一直在開發公司內部使用的巡檢系統,在涉及埠掃描這塊,為了保證速度和準確性,方案是使用Masscan+Nmap:Masscan速度快,先使用Masscan進行一遍全埠探測。再使用Nmap對已經探測出來的埠進行復掃和Banner識別,Nmap的準確性較高,但速度較慢,所以通過這種方式保證埠掃描的準確性。
這是我對於埠掃描過程中尋找速度與準確度之間平衡點的淺顯思路。前幾天剛好看到一篇國外的文章,介紹的東西遠比我理解的更深入,故翻譯出來一起學習。
如下內容為翻譯內容,原文連結如下:《inding the Balance Between Speed & Accuracy During an Internet-wide Port Scanning》[1]
0x01 介紹偵察是每個bug bounty(漏洞賞金)和滲透測試過程中最重要的階段,一次好的偵察能決定成敗。偵察可以分為兩類:主動和被動。在主動偵察期間主要使用的方法之一就是埠掃描。滲透測試人員和bug hunters(漏洞賞金獵人)使用埠掃描確定目標主機和網絡上的哪些埠是開放的,以及識別在這些埠上運行的服務。
但是,埠掃描總是需要在速度和精度之間進行權衡。在滲透測試期間,測試人員的時間都是有限的;而在bug bounty過程中,大家都是爭先恐後的發現並提交漏洞,拼的是速度。這些原因迫使我們在埠掃描時優先考慮的是速度,而不是精度。而在於時間賽跑的過程中,我們可能會錯過一些開放的埠,而恰巧這些埠可能就存在漏洞,並且能成功利用。
本次研究旨在利用開源和大家熟知的工具在埠掃描期間找到速度和準確度之間的平衡。
0x02 埠掃描概述埠掃描是偵察期間最常用的技術之一。滲透測試人員和bug bonty用於識別主機上可用的開放埠,以及識別這些開放埠上運行的服務。
埠掃描器可以根據他們的操作方式分類為:面向連接(同步模式)掃描器和無連接的(異步模式)掃描器。
面向連接(同步模式)這種類型的掃描器想目標埠發送請求並等待響應,直到超時時間到期。這種類型掃面器的缺點是性能比較慢,因為掃描器在當前連接關閉之前不會去掃描下一個目標埠或ip。
面向連接的掃描器好處是它們更準確,因為它們可以識別丟棄的數據包。面向連接掃描器最流行就是我們熟知的Nmap。
無連接(異步模式)無連接掃描器不依賴於當前被探測埠的完成來啟動下一個埠,因為它們有單獨的發送和接受線程。這允許它們進行高速掃描。但是,這些掃描器的結果可能不太準確,因為它們無法檢測丟失的數據包。
Masscan和Zmap是目前最流行的兩種無連接掃描器。
0x03 Nmap VS Masscan本次研究只包括Nmap和Masscan。雖然Zmap是一個快速的掃描器,並且掃描結果還不錯。但是根據經驗,即使同時運行多個掃描任務,Zmap的掃描速度仍然很慢。
雖然Nmap和Masscan都提供了良好的性能、特性和掃描結果。但它們 仍然有自己的弱點。下表展示了這兩種工具的優缺點。
基於上面列出的工具的有點和缺點,在試圖找到速度和準確度之間的平衡時,確定了一下解決方案和問題。
解決方案以下是基於工具的優點而形成的:
將Nmap的準確性及其其他的功能與Masscan的速度相結合。使用Masscan執行初始埠的掃描,以識別開放的埠和開埠的主機。使用Masscan的結果(已識別的開放埠和主機)作為Nmap的輸入,以進行詳細的埠掃描。問題雖然上面列出的想法很好,但是我們仍然需要解決每個工具的缺點。具體來說,我們需要解決的有:
Masscan在高速(rates)掃描大埠範圍時的不準確性(參見文末參考資料的第2個連結)。0x05 研究配置目標網絡選擇一下子網作為本次研究的網絡目標:
目標子網AA.A.0.0/16BB.B.0.0/16CC.C.0.0/16DD.D.0.0/16測試用例對於本次研究,兩種工具都有自己的一些測試用例。這些測試用例是每種工具中可用的不同選項(參數)的變化。這些測試用例旨在解決工具的缺點,並利用它們的優點在速度和準確性之前找到平衡點。
Masscan:以不同的速率(rates)定期掃描所有的TCP埠。將/16的目標子網差分為/20,並運行X個並發masscan任務,每個任務的速率為Y。將1-65535的埠範圍劃分為幾個範圍,並運行X個並發的Masscan任務,每個任務的速率為Y。Nmap:掃描Masscan識別的開放埠和主機的組合列表。在有限的時間內不可能涵蓋所有選項的每個變化/組合,因此僅涵蓋上述內容。
對於使用並發任務的測試用例,使用了工具GNU Parallel[3]。如果你對這個工具還是個新手,請查看詳細的教程[4]。
0x06 範圍和限制該研究使用以下版本的工具進行:Nmap v7.70和Masscan v1.0.5-51-g6c15edc;僅使用了最流行和開源的工具(不包括Zmap,因為它一次只能掃描一個埠;即使運行多個任務,也會導致掃描速度非常慢);埠掃描僅來自一臺機器,且這臺機器的ip地址是固定ip;由於掃描機器不支持PF_RING,因此Masscan的速率僅限於250kpps(每秒數據包);並不是所有的測試用例都是由有限的資源而進行的(這樣做非常耗時)。0x07 Masscan的測試用例和測試結果本節詳細介紹了使用Masscan執行的不同測試用例和其測試結果。
測試用例 #1:使用不同的速率定期掃描所有的TCP埠這個測試用例沒啥特別之處,這只是Masscan的正常掃描,只是速率不同而已。
以下命令用於啟動此掃描用例的掃描任務:
masscan -p 1-65535 --rate RATE--wait 0 --open TARGET_SUBNET -oG TARGET_SUBNET.gnmaprate(掃描速率)參數的設置:
在實驗過程中,我得VPS可以運行的最大速率僅為250kpps左右。這是因為掃描的機器不支持PF_RING。
圖表(由於最大速率是250kpps,故圖表中的為250k、100k和50k的對比):
觀察:
慢速率會導致發現更多的開放埠,但是代價就是掃描花費的時間更長。
測試用例 #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)以下是該代碼的運行截圖:
每項任務所用的速率都是基於掃描機器能夠處理的速率最大化思想。在我的例子中,我的掃描機器最大只能處理250kpps,所以如果我要運行5個並行任務,每個任務可使用50kpps的速率。
由於機器的最大速率不是「絕對」的(在本次測試中不完全都是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個任務/每個任務的速率是100kpps (--rate 100000 )5個任務/每個任務的速率是50kpps (--rate 50000)20個任務/每個任務的速率是10kpps (--rate 10000)說明:
大家可以注意到,我上面說的任務數和速率中第一個(5個任務/每個任務的速率是100kpps),我計算錯了。因為它的總速率是500kpps,而我的機器只能處理250kpps。儘管如此,這個的測試結果仍然是有價值的,將可以在下面的圖表裡看到。其他的組合,例如10個任務,每個任務的速率20kpps,這樣是可行的。但是由於時間和預算有限,我不能把所有可能的組合都涵蓋了。圖表如下:
觀察:
當前的方案會比常規掃描(測試用例 #1)快2-3倍,但是導致開放的埠更少了。使用掃描機器的最大速率將導致掃描出的開放埠數更少(五個任務/每個任務100k的掃描速率)。少任務數&高掃描速率(例如5個任務/每個任務的速率50k)比多任務數&低掃描速率(例如20個任務/每個任務的速率10k)的效果好。測試用例 #3:將1-65535埠範圍拆分為多個更小的範圍,運行X個Masscan並發任務,每個任務的掃描速率為Y第三個測試用例是為了解決在掃描大埠範圍的時候,上文提到的Masscan的問題(參見文末參考資料的第2個連結),特別是整個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埠範圍分為四種拆分方式,如下所示,每種拆分方式包含任務和速率的組合/變化。
拆分方式 #1:拆分為5個埠範圍1-13107
13108-26214
26215-39321
39322-52428
52429-65535任務數和速率如下:
5個掃描任務/每個任務50k的掃描速率 (--rate 50000)2個掃描任務/每個任務100k的掃描速率 (--rate 100000)圖表如下:
拆分方式 #2:拆分為2個埠範圍1-32767
32768-65535任務數和速率如下:
2個掃描任務/每個任務100k的掃描速率 (--rate 100000)2個掃描任務/每個任務125k的掃描速率 (--rate 125000)圖表如下:
拆分方式 #3:拆分為8個埠範圍1-8190
8191-16382
16383-24574
24575-32766
32767-40958
40959-49151
49152-57343
57344-65535任務數和速率如下:
4個掃描任務/每個任務50k的掃描速率 (--rate 50000)2個掃描任務/每個任務100k的掃描速率 (--rate 100000)圖表如下:
拆分方式 #4:拆分為4個埠範圍1-16383
16384-32767
32768-49151
49152-65535任務數和速率如下:
2個掃描任務/每個任務100k的掃描速率 (--rate 100000)本次測試我之所以只使用了一種任務數&速率的組合,是因為我意識到我已經超過了每個月的帶寬限制。這樣我不得不多付100+美元。
圖表如下:
觀察:
下面列出的觀察結果涵蓋了上面提到的所有4個拆分方式的方案。
拆分埠範圍會掃描出更多的開放埠(這樣解決了Masscan在掃描大範圍埠時的問題(參見文末參考資料的第2個連結);使用更少的並行任務(本次測試中是2個並行任務)會掃描出更多的開放埠;在所有的拆分方案的測試中,拆分為5個埠範圍(拆分方式# 1)的掃描結果最佳。原始數據
下表顯示了使用上述不同Masscan測試用例進行實驗的原始數據:
Masscan結論:根據使用Masscan進行的所有測試用例的結果,得出以下結論:
以100%的CPU利用率運行掃描任務,會導致埠開放性降低;使用機器能運行的最大速率容量進行掃描會導致更少的埠開放;當使用並發任務時,較少的任務數會掃描出更多的開放埠;對於埠範圍拆分的方式,(拆分方式 #1 和拆分方式 #4)的掃描結果是最佳的。0x08 Nmap的測試用例和測試結果在此階段,只執行版本掃描。Nmap的NSE,OS探測和其他掃描功能都沒有涉及。Nmap的線程被限制為T4,等同於如下命令:
--max-rtt-timeout=1250ms --min-rtt-timeout=100ms --initial-rtt-timeout=500ms --max-retries=6 --max-scan-delay=10ms以下Nmap選項也用於模擬masscan使用的選項。這些選項應用於所有Nmap測試用例。
使用的Nmap選項如下:
隨機選擇掃描對象(--randomize-hosts)測試用例 #1:定期掃描所有的TCP埠這個測試用例只是使用Nmap的正常掃描,所以沒啥特別之處。使用的命令如下:
sudo nmap -sSV -p- -v --open -Pn -n --randomize-hosts -T4 TARGET_SUBNET -oA OUTPUT觀察:
掃描了四天半以後,掃描任務仍然沒有完成。這就是前文提到的缺點之一:掃描大型網絡目標的時候,Nmap的速度非常慢;測試用例 #2:使用X個並發任務掃描所有的TCP埠在這種情況下,我嘗試通過運行並發的Nmap掃描任務來解決Nmap的低性能問題。通過將目標子網劃分為較小的子網塊來完成,就像上面Masscan測試的那樣。同樣,下面的代碼(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的子網
觀察:
使用64個並發任務:/16的目標子網拆分為/24的子網
觀察:
測試用例 #3: 掃描Masscan識別出的開放埠和主機的組合列表這個測試用例背後的想法是,首先獲得一個主機列表和一個由Masscan掃描出的開放埠的組合列表。這個開放埠的組合列表被用作基線(如下圖圖表中的綠色條所示),以確定下面的Nmap測試用例能否能檢測出更多或更少的k開放埠。
例如,Masscan檢測到300個開放埠,而常規Namp掃描檢測到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 {}"使用的並發任務數:
圖表如下:
觀察:
運行常規的Nmap掃描時,CPU的利用率僅為10%左右;
常規的Nmap掃描發現了更多的開放埠,而並發的Nmap掃描發現的開放埠較少一些。
與基線(上面圖表中的綠色條)相比,在某些目標網絡(子網A)上識別出更多的開放埠,而在其他的網絡目標(子網B和子網C)上檢測到的開放埠較少,在某些網絡目標(子網D)上沒有太大差異。
Nmap檢測到的其他開放埠先看下面的表格。例如,讓我們假設Masscan在每臺主機上檢測到以下的開放埠(表格第2列)。在運行Nmap掃描時,Masscan檢測到的所有開放埠將用作Nmap的目標埠(表格第3列)。
在我們的示例中,Nmap在完成掃描後檢測到的新開放的埠(第4列中的粗體文字)。這種情況是怎麼發生的?Masscan是一個異步的掃描器,主機192.168.1.2和192.168.1.3上可能丟失了22埠。由於我們合併了每個主機上檢測到的開放埠,並將它們作為Nmap的目標埠,因此這個丟失的22埠將再次進行探測。需要注意的是,無法保證Nmap能夠將其檢測為開放狀態,因為還有其他可能影響掃描結果的因素。
主機Masscan檢測到的埠Nmap掃描的目標埠Nmap運行後檢測到的開放埠192.168.1.122,80,44322,80,443,8080,888822,80,443192.168.1.28080,888822,80,443,8080,888822,8080,888192.168.1.380,44322,80,443,8080,888822,80,443測試用例 #4 掃描由Masscan識別的特定主機上的特定開放埠這個與之前的測試用例有點類似。在這個用例中,我沒有將Masscan檢測到的所有開放埠與每個主機組合在一起。無論Masscan在特定主機上檢測到哪些開放埠,Nmap都將使用相同的埠作為目標埠。下表說明了我們這個測試用例中的操作:
主機Masscan檢測到的埠Nmap掃描的目標埠192.168.1.122,80,44322,80,443192.168.1.28080,88888080,8888192.168.1.380,44380,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,請查看使用教程(參見文末參考資料第4個連結)。
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下圖展示了測試用例執行時,發生的一個片段。如下圖所示,使用parallel運行10個並發的Nmap掃描。
使用的並發任務數:
圖表如下:
觀察:
更多的並發任務和以100%的CPU利用率進行掃描時,檢測出更少的開放埠。10個和50個Nmap並發任務,掃描結果差別不大,因此建議可以運行50個並發任務,以減少掃描時間。此測試用例比測試用例 #3的掃描速度略快,但是檢測出的開放埠較少。原始數據
下表顯示了使用上述不同的Nmap測試用例進行實驗的原始數據:
Nmap結論:根據使用Nmap進行的實驗結果,得出以下結論:
測試用例 #3(掃描Masscan識別出的開放埠和主機的組合列表)可獲得最佳的結果。這也是推薦的方法,因為可以發現額外的埠開放;以100%的CPU利用率進行掃描,會導致檢測出更少的開放埠;使用並發任務時,更少的任務數會導致檢測出更多的開放埠;0x09 研究結論推薦的掃描方法根據對Masscan和Nmap進行的多個測試用例的測試結果,建議採用以下方法在埠掃描期間實現速度和精度之間的平衡:
首先運行2或3個並發的Masscan任務,所有的65535個埠分為4-5個更小的範圍;獲取主機列表以及Masscan掃描出的開放埠的組合列表;使用這些列表作為Nmap的掃描目標並執行常規Nmap掃描。注意事項對於這兩種掃描埠的工具,應採用以下的預防措施進行規避,因為它們會導致檢測到的開放埠更少:
0x10 最後的想法雖然這項研究提供了一種如何在網際網路埠掃描期間平衡速度和準確性的方法,但讀者不應將此結論視為100%可靠。由於時間和預算有限,研究期間沒有涵蓋其他的影響因素。最值得注意的是,在整個研究期間僅使用一個IP位址進行掃描並不是一個好的設置。因為在我多次掃描相同的目標網絡後,機器的IP位址可能會以某種方式被拉黑,這可能導致檢測到的開放埠數量不太一致。
請重新查看0x06 範圍和限制部分,因為從中可以很好的理解影響本研究結果的一些因素。
0x11 參考資料[1]inding the Balance Between Speed & Accuracy During an Internet-wide Port Scanning: https://captmeelo.com/pentest/2019/07/29/port-scanning.html
[2]Masscan在高速率(rates)掃描大埠範圍時結果不太準確的Issues: https://github.com/robertdavidgraham/masscan/issues/365
[3]GNU Paralle工具: https://www.gnu.org/software/parallel/
[4]GNU Paralle工具使用教程: https://www.gnu.org/software/parallel/parallel_tutorial.html