python-nmap實現(xiàn)python利用nmap進行掃描分析
前言
Nmap是一個非常用的網(wǎng)絡/端口掃描工具,如果想將nmap集成進你的工具里??梢允褂胮ython-nmap這個python庫,它提供了一個簡單的接口來使用nmap進行掃描。
python-nmap的基本使用
在安裝這個模塊之前,請?zhí)崆鞍惭b好nmap工具,python-nmap模塊自身不提供任何掃描功能,只是提供一個接口來使用namp。
pip install python-nmap
目前最新版本是0.7.1支持python3,python2的版本詳細參考:https://pypi.org/project/python-nmap/
PortScanner掃描
python-nmap其中的一個核心類是PortScanner,它負責與nmap掃描器進行交互,用于執(zhí)行掃描并管理掃描結果。
首先需要創(chuàng)建一個PortScanner實例:
import nmap nm = nmap.PortScanner()
執(zhí)行掃描:
使用 scan() 方法執(zhí)行網(wǎng)絡掃描。可以指定目標主機、端口范圍、掃描類型等參數(shù)。
def scan( # NOQA: CFQ001, C901
self, hosts="127.0.0.1", ports=None, arguments="-sV", sudo=False, timeout=0
):
"""
:param hosts: 主機字符串,如 nmap 使用的 'scanme.nmap.org' 或 '198.116.0-255.1-127' 或 '216.163.128.20/20'
:param ports: 端口字符串,如 nmap 使用的 '22,53,110,143-4564'
:param arguments: nmap 參數(shù)字符串 '-sU -sX -sC'
:param sudo: 如果為 True,則使用 sudo 啟動 nmap
:param timeout: 整數(shù),如果大于零,將在指定秒數(shù)后終止掃描,否則將無限期等待
:returns: 掃描結果作為字典
"""
例如掃描主機和端口,scan() 返回一個字典作為掃描結果。
scan_result = nm.scan("192.168.88.150", "22")

獲取掃描結果:
PortScanner封裝了一系列方法,可以方便的獲取掃描結果中我們想要的數(shù)據(jù),而不需要去手動的解析上面返回的這一長串字典數(shù)據(jù)。
1、all_hosts() 獲取所有掃描的主機
all_hosts = nm.all_hosts()
返回一個排序后的列表,包含所有掃描的ip地址。
['192.168.88.150']
2、command_line() 獲取當前用于掃描的nmap命令
command_line = nm.command_line()
返回當前的掃描命令,這里的參數(shù)列表中的 -oX - 它會讓nmap的把xml格式作為標準輸出。
nmap -oX - -p 22 -sV 192.168.88.150
3、scaninfo() 獲取當前掃描信息
scaninfo = nm.scaninfo()
返回一個當前掃描信息的字典。
{'tcp': {'method': 'syn', 'services': '22'}}
4、scanstats() 獲取掃描統(tǒng)計信息
scan_stats = nm.scanstats()
返回一個當前描統(tǒng)計信息的字典,包括掃描時間等。
{'timestr': 'Mon Dec 30 17:25:17 2024', 'elapsed': '6.59', 'uphosts': '1', 'downhosts': '0', 'totalhosts': '1'}
5、has_host() 檢查特定主機是否被掃描
has_host = nm.has_host("192.168.88.150")
如果有掃描結果返回True,否則返回False。
6、以 CSV 格式獲取掃描結果
csv_result = nm.csv()
返回csv格式的文本輸出。
host;hostname;hostname_type;protocol;port;name;state;product;extrainfo;reason;version;conf;cpe
192.168.88.150;;;tcp;22;ssh;open;OpenSSH;"Ubuntu Linux; protocol 2.0";syn-ack;8.9p1 Ubuntu 3ubuntu0.10;10;cpe:/o:linux:linux_kernel
寫一個小案例,掃描一個網(wǎng)段內(nèi)的所有存活主機。
import nmap
nm = nmap.PortScanner()
nm.scan(hosts='192.168.88.0/24', arguments='-sn')
hosts_list = [(x, nm[x]['status']['state']) for x in nm.all_hosts()]
for host, status in hosts_list:
if status == 'up':
print(f'{host} status: {status}')

除了上述PortScanner類提供的幾個基本方法,其實還可以更加靈活的運用。
PortScannerAsync異步掃描
對于需要同時掃描多個主機或端口范圍的情況,使用PortScanner同步掃描,并不是一個好辦法。好在python-nmap提供了一個異步掃描的方案,PortScannerAsync使用多進程技術異步掃描,避免同步掃描可能導致的阻塞,提高了掃描效率。
首先需要創(chuàng)建一個PortScannerAsync實例:
import nmap nm_async = nmap.PortScannerAsync()
同樣是使用 scan() 方法執(zhí)行掃描:
def scan( # NOQA: CFQ002
self,
hosts="127.0.0.1",
ports=None,
arguments="-sV",
callback=None,
sudo=False,
timeout=0,
):
"""
:param hosts: 主機字符串,格式與 nmap 使用的格式相同,例如'scanme.nmap.org' 或 '198.116.0-255.1-127' 或 '216.163.128.20/20'。
:param ports: 端口字符串,格式與 nmap 使用的格式相同,例如 '22,53,110,143-4564'。
:param arguments: nmap 的參數(shù)字符串,例如 '-sU -sX -sC'。
:param callback: 回調(diào)函數(shù),該函數(shù)以(主機,掃描數(shù)據(jù))作為參數(shù)。
:param sudo: 如果為真,則使用 sudo 啟動 nmap。
:param timeout: 整數(shù),如果大于零,將會在指定秒數(shù)之后終止掃描,否則將無限期等待。
"""
和PortScanner的scan()很類似,但是多了一個callback參數(shù),需要傳一個回調(diào)函數(shù),用于掃描結束后的結果處理。
import nmap
# 定義回調(diào)函數(shù)(掃描結果處理)
def scan_callback(host, data):
"""
:param host: 掃描完主機ip地址
:param data:掃描結果
"""
print(host, data)
nm_async = nmap.PortScannerAsync()
hosts = '192.168.88.0/24'
ports = '1-1000'
arguments = '-sS'
if __name__ == '__main__':
# 創(chuàng)建一個新的進程掃描,避免主進程阻塞
nm_async.scan(hosts, ports, arguments, callback=scan_callback)
while nm_async.still_scanning():
# still_scanning判斷是否還在掃描
print("scanning...")
nm_async.wait(1)

使用異步掃描,類似于放到后臺掃描,避免了一直阻塞主進程。當然使用Process和PortScanner也可以實現(xiàn)一樣的效果,PortScannerAsync是python-nmap封裝好了,開箱即用。
python-nmap的源碼分析
python-nmap其實已經(jīng)比較完善了,但是如果想用做一些二次開發(fā),不妨來看看源碼,分析分析它的的工作流程。
這里主要看一下PortScanner和PortScannerAsync這兩類。其中PortScanner是python-nmap的核心類,scan方法又是PortScanner的核心方法,其實只要了解了scan方法就知道python-nmap的整個邏輯了。
PortScanner的全貌:

后面6個函數(shù)前面介紹過,前面的幾個函數(shù)主要也是為scan函數(shù)服務的,重點看scan函數(shù)。
scan函數(shù)的邏輯并不復雜,簡單說,接收用戶輸入,構建完整的nmap命令行參數(shù)列表,交給nmap掃描, 獲取nmap掃描結果,解析掃描結果并返回。
scan函數(shù)簡化后的代碼邏輯:
def scan(self, hosts="127.0.0.1", ports=None, arguments="-sV", sudo=False, timeout=0):
# 對輸入?yún)?shù)(主機、端口、掃描參數(shù)等)進行類型檢查和合法性驗證
if sys.version_info[0] == 2:
......
else:
......
# shlex模塊對主機和掃描參數(shù)進行分割處理
h_args = shlex.split(hosts)
f_args = shlex.split(arguments)
# 構建完整的nmap命令行參數(shù)列表
args = ([self._nmap_path, "-oX", "-"] + h_args + ["-p", ports] * (ports is not None) + f_args)
# 啟動nmap進程
p = subprocess.Popen(args, bufsize=100000, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,)
# 超時處理
if timeout == 0:
(self._nmap_last_output, nmap_err) = p.communicate()
else:
......
return self.analyse_nmap_xml_scan(nmap_xml_output=self._nmap_last_output, nmap_err=nmap_err)
- 它首先對輸入?yún)?shù)(主機、端口、掃描參數(shù)等)進行類型檢查和合法性驗證,確保符合nmap命令的要求。
- 然后,使用shlex模塊對主機和掃描參數(shù)進行分割處理,構建完整的nmap命令行參數(shù)列表。
- 在執(zhí)行掃描過程中,通過subprocess.Popen啟動nmap進程,并根據(jù)設置的超時時間等待掃描完成或進行超時處理。
- 構建nmap命令行參數(shù)列把XML格式作為標準輸出。所以定義一個analyse_nmap_xml_scan函數(shù)來解析nmap的xml輸出,該函數(shù)會將nmap生成的xml掃描結果解析為一個結構化的Python字典。
掃描結果的解析與存儲也是重要一環(huán),它在analyse_nmap_xml_scan函數(shù)實現(xiàn)。
analyse_nmap_xml_scan函數(shù)簡化后的代碼邏輯:
def analyse_nmap_xml_scan( self, nmap_xml_output=None, nmap_err=nmap_err):
if nmap_xml_output is not None:
self._nmap_last_output = nmap_xml_output
scan_result = {}
# 將XML字符串轉換為元素樹
try:
dom = ET.fromstring(self._nmap_last_output)
except Exception:
pass
# 掃描結果存儲結構, get等方法拿到樹中的數(shù)據(jù)
scan_result["nmap"] = {
"command_line": dom.get("args"),
"scaninfo": {
"timestr": dom.find("runstats/finished").get("timestr"),
......
},
}
return scan_result在analyse_nmap_xml_scan函數(shù)中,它會從nmap_xml_output拿到nmap的xml結果輸出,再使用xml.etree.ElementTree模塊對nmap掃描生成的xml輸出進行解析。使用fromstring方法將xml字符串轉換為可操作的元素樹,然后遍歷樹的各個元素,提取關鍵信息。
通過遍歷xml樹結構,提取諸如掃描命令行信息、掃描統(tǒng)計數(shù)據(jù)、主機詳細信息。對于每個主機,分別解析其地址信息、主機名信息、端口信息以及腳本輸出信息,并將這些信息按照層次結構存儲在scan_result字典中,也就是scan函數(shù)最后返回的內(nèi)容。
其實nmap提供5種不同的輸出格式,默認的方式是interactive output發(fā)送給標準輸出。但-oX -會讓nmap輸出xml到標準輸出stdout,而xml輸出對于程序處理非常方便的。
PortScannerAsync類也很清晰,它使用PortScanner類進行端口掃描,multiprocessing庫的Process類用于創(chuàng)建進程,以此實現(xiàn)異步掃描。
PortScannerAsync類簡化后的代碼邏輯:
def __scan_progressive__(self, hosts, ports, arguments, callback, timeout):
# 此函數(shù)在一個單獨的進程中執(zhí)行掃描操作,并調(diào)用回調(diào)函數(shù)處理結果
try:
scan_data = self._nm.scan(host, ports, arguments, timeout)
except Exception:
scan_data = None
if callback is not None:
callback(host, scan_data)
return
class PortScannerAsync(object):
def __init__(self):
self._process = None
self._nm = PortScanner() #創(chuàng)建一個PortScanner實例,用于執(zhí)行掃描操作
return
def scan(self, hosts="127.0.0.1", ports=None, arguments="-sV", callback=None, timeout=0):
if sys.version_info[0] == 2:
......
else:
......
self._process = Process( # 創(chuàng)建一個新的進程對象,將 __scan_progressive__ 函數(shù)作為目標函數(shù)
target=__scan_progressive__,
args=(self, hosts, ports, arguments, callback, timeout),
)
self._process.daemon = True
self._process.start()
return__scan_progressive__函數(shù),它是執(zhí)行掃描任務和調(diào)用回調(diào)函數(shù)的核心部分,調(diào)用 self._nm.scan 方法進行掃描,調(diào)用 callback 函數(shù)以處理掃描結果。
scan函數(shù)會創(chuàng)建一個新的進程并指定 _scan_progressive_ 函數(shù)作為目標函數(shù),將自身實例、掃描參數(shù)和回調(diào)函數(shù)等傳遞給該函數(shù)。
在目標函數(shù)中,針對每個發(fā)現(xiàn)的主機,調(diào)用PortScanner實例的scan方法進行掃描,并在掃描完成后調(diào)用用戶提供的回調(diào)函數(shù),將主機信息和掃描結果傳遞給回調(diào)函數(shù)進行處理。
PortScannerAsync還提供了一些管理進程的函數(shù),用于擴展。

以上就是python利用nmap實現(xiàn)掃描分析的詳細內(nèi)容,更多關于python nmap的資料請關注腳本之家其它相關文章!
相關文章
Python PyQt5運行程序把輸出信息展示到GUI圖形界面上
這篇文章主要介紹了Python PyQt5運行程序把輸出信息展示到GUI圖形界面上,本文通過截圖實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04
selenium攜帶cookies模擬登陸CSDN的實現(xiàn)
這篇文章主要介紹了selenium攜帶cookies模擬登陸CSDN的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01
Python實現(xiàn)基于Excel數(shù)據(jù)繪制棋盤圖
這篇文章主要為大家介紹了如何根據(jù)可視化的需要,利用Python將Excel中的數(shù)據(jù)用棋盤圖的樣式來展示,文中的示例代碼簡潔易懂,需要的可以參考一下2023-07-07
解決webdriver.Chrome()報錯:Message:''chromedriver'' executable n
這篇文章主要介紹了解決webdriver.Chrome()報錯:Message:'chromedriver' executable needs to be in Path ,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-06-06
Python內(nèi)置模塊hashlib、hmac與uuid用法分析
這篇文章主要介紹了Python內(nèi)置模塊hashlib、hmac與uuid用法,結合實例形式較為詳細的分析了hashlib、hmac與uuid模塊的概念、功能及簡單使用方法,需要的朋友可以參考下2018-02-02

