Bash實現快速埠識別與服務監控
一、背景
關於埠識別與服務監控問題,早有大牛提供過masscan掃埠+nmap掃服務思路。但在親自實踐過程中,發現最致命的問題是nmap掃描速度太慢,導致無法接受這個掃描時長,尤其是存在大量ip的情況下。於是考慮nmap引數調優、多程序掃描等方式,但效果甚微,最後與幾位未曾相識的大牛們在群裡討論過之後,最終得到一個比較滿意的結果,下面就詳細得分享下這個專案。
二、思路
總體思路依然masscan掃埠+nmap掃服務,眾所周知,masscan掃埠的速度是相當得快,所以關於埠掃描速度這塊不需要考慮,只需對輸出結果進行整理即可。最主要的是要考慮如何在有限得資源下來提升nmap掃服務的速度,整個專案實現過程磕磕絆絆,最終總結出以下三個重難點:
1.進行nmap引數調優,減少不必要的等待時長; 2.在存在大量ip與開放埠的情況下,儘可能減少nmap初始化次數,以便能有效得節約系統資源; 3.實現nmap併發掃描,提升掃描效率。
其中重中之重是第3點,一開始是考慮通過for迴圈來實現多程序後臺併發執行,但結果是掃描速度提升效果不顯著,而且系統性能也被消耗得厲害。後來與借鑑了幾位大佬的意見之後,開始考慮用佇列來實現併發。
三、具體實現
囉嗦了這麼多,下面就來看一下具體實現,本人非程式猿,擼個指令碼都感覺是十分崩潰的,真是羨慕各位又會寫程式又懂安全人又風趣的gg們。
1.masscan開放埠掃描
主要分為兩個模組:開放埠掃描+掃描結果處理
a.開放埠掃描
masscan -p 1-65535 --rate 100000 --open-only -iL /data/portscan/iplist/allip.txt --excludefile /data/portscan/iplist/ip.exclude
這裡主要提下–rate引數,–rate引數是指發包速率,需要根據你的實際頻寬來配置,高了容易誤報,低了影響掃描速率。
b.掃描結果處理
掃描結果處理是為下一步使用nmap進行服務探測做準備的。服務探測有兩種方式可選擇,“單ip單埠併發掃描”或者“單ip多埠併發掃描”。上一小節思路重難點的第2點已經提過,“在存在大量ip與開放埠的情況下,儘可能減少nmap初始化次數,以便能有效得節約系統資源”,所以最終選擇了“單ip多埠併發掃描”方式。相應得,masscan埠掃描結果也要按此方式進行處理。
下面上程式碼,一系列sed/awk……
#掃描完後只保留存活ip與埠資訊,並寫在 port.list檔案中
masscan -p 1-65535 --rate 100000 --open-only -iL /data/portscan/iplist/allip.txt --excludefile /data/portscan/iplist/ip.exclude | sed 's/\/tcp//g' |awk -F " " {'print $6,$4'}>/data/portscan/portresult/port.list
#對port.list中結果去重後儲存在port.list.tmp檔案中
sort /data/portscan/portresult/port.list | uniq > /data/portscan/portresult/port.list.tmp
#將port.list.tmp檔案中結果按“ip 埠1,埠2,埠3,……”方式處理後儲存在port.list.nmap中
awk '{a[$1]=$2","a[$1]}END{for(i in a){print i,a[i]}}' /data/portscan/portresult/port.list.tmp | sed "s/,$//g" > /data/portscan/portresult/port.list.nmap
2.服務版本探測
這裡主要考慮兩個方面,nmap引數調優和佇列控制併發掃描。
a.nmap引數調優
nmap -T4 -Pn -sV -n -p $port $ip
-T4:將掃描延遲降低到10ms;
-sV:對服務的版本資訊進行探測,加上這個引數後更耗時,但是探測結果可以細緻到版本號,主要還是看各位需求。
b.佇列控制併發掃描
佇列控制可以使系統達到較好的利用率,執行緒數可以自己根據需要進行調整,我目前使用一臺8核24G的虛擬機器跑1w+個ip,40w+個埠,12個小時內完成所有的埠與應用識別。上程式碼:
#建立有名管道
[ -e /tmp/fd1 ] || mkfifo /tmp/fd1
#建立檔案描述符,以可讀(<)可寫(>)的方式關聯管道檔案,這時候檔案描述符3就有了有名管道檔案的所有特性
exec 3<>/tmp/fd1
#關聯後的檔案描述符擁有管道檔案的所有特性,所以這時候管道檔案可以刪除,我們留下檔案描述符來用就可以了
rm -rf /tmp/fd1
#併發執行的程序數量
thread=30
for ((i=1;i<=$thread;i++))
do
#&3代表引用檔案描述符3,這條命令代表往管道里面放入了一個"令牌"
echo >&3
done
#總的ip數目
ipnum=`wc -l /data/portscan/iplist/port.list.nmap | awk {'print $1'}`
for ((i=1;i<=$ipnum;i++))
do
#代表從管道中讀取一個令牌
read -u3
{
#提取ip地址和埠號
ip=`sed -n ""$i"p" /data/portscan/portresult/port.list.nmap| awk {'print $1'}`
port=`sed -n ""$i"p" /data/portscan/portresult/port.list.nmap| awk {'print $2'}`
#當開放埠數量超過500時,直接掃全量埠,這樣反而速度會更快
if [[ `echo $port | awk -F "," {'print NF'}` -gt 500 ]] ; then
port="1-65535"
fi
#掃描完成後立即將結果按“ip地址 nmap 埠號 開放狀態 開放服務 版本號”方式進行處理
/usr/bin/nmap -T4 -Pn -sV -n -p $port $ip | grep -v "Nmap" |grep -v "SUBMIT INDIVIDUALLY"|grep -v "MAC Address"| grep -v "Host is up" | grep -v "Service Info"| grep -v -E "SF:" | grep -v "SF-"|grep -v "please submit" | grep -v -E "PORT\s+STATE" |grep -v "Service detection"|sed '/^\s*$/d' | sed 's/^/'"$ip"' nmap /g'|sed 's/\/tcp//g' | sed 's/\s\+/ /g' >>/var/log/nmap 2>> /data/portscan/servicescan.log
#命令執行到最後,把令牌放回管道
echo >&3
} 2>> /data/portscan/servicescan.log &
done
wait
exec 3<&- #關閉檔案描述符的讀
exec 3>&- #關閉檔案描述符的寫
四、結語
接下來考慮使用掃描結果進行高危埠監控和服務識別了,我是結合splunk來做分析的,各位是願意接入資料分析平臺還是直接擼指令碼就看手上的資源和自己的興趣了。另外,有興趣的小夥伴還可以試著用python來實現。
*本文原創作者:xyl870612,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載