返回文章列表

Nmap掃描器工作原理與Python應用

本文探討了Nmap掃描器的工作原理,涵蓋了各種掃描技術,例如TCP Connect掃描、TCP Stealth掃描、UDP掃描、TCP ACK掃描、TCP NULL掃描、TCP FIN掃描和TCP

網路安全 Python

Nmap 作為一款功能強大的網路掃描工具,在網路安全領域扮演著重要的角色。其豐富的掃描技術,從基本的 TCP Connect 掃描到更為隱蔽的 TCP Stealth 掃描,都能幫助安全人員探測目標網路的開放埠和服務。理解 Nmap 如何定義埠狀態(開啟、關閉、過濾、未過濾)對於準確解讀掃描結果至關重要。而 python-nmap 模組的出現,更是讓開發者能夠以更便捷的方式在 Python 環境中使用 Nmap 的強大功能,自動化執行埠掃描和網路偵察任務,提升效率。文章中提供的程式碼範例,涵蓋了同步掃描、CSV 格式輸出等實用技巧,讓讀者可以快速上手,並根據自身需求進行客製化開發。

使用Nmap掃描器的工作原理

在前面的內容中,我們看到了Nmap提供的主要掃描技術:

  • sT(TCP Connect 掃描):此選項通常用於檢測埠是否開啟或關閉,但它也是最容易被入侵檢測系統(IDS)稽核和監控的機制。使用此選項時,如果伺服器在傳送SYN旗標的封包時回應包含ACK旗標的封包,則埠是開啟的。
  • sS(TCP Stealth 掃描):這是一種根據TCP Connect 掃描的掃描型別,不同之處在於埠上的連線並未完全建立。此選項包括在傳送SYN旗標的封包之前檢查目標的回應封包。如果目標回應包含RST旗標的封包,則可以檢查埠是否開啟或關閉。
  • sU(UDP 掃描):這是一種根據UDP協定的掃描型別,傳送UDP封包以確定埠是否開啟。如果回應是另一個UDP封包,則意味著埠是開啟的。如果回應傳回Internet控制訊息協定(ICMP)型別3(目的地不可達)的封包,則埠未開啟。
  • sA(TCP ACK 掃描):此型別的掃描讓我們知道目標機器是否執行任何型別的防火牆。此掃描選項向目標機器傳送包含ACK旗標的封包。如果遠端機器回應包含RST旗標的封包,則可以確定埠未被任何防火牆過濾。如果我們沒有收到遠端機器的回應或收到ICMP封包,則可以確定有防火牆過濾傳送到指定埠的封包。
  • sN(TCP NULL 掃描):這是一種傳送不含任何旗標的TCP封包到目標機器的掃描型別。如果遠端機器傳回有效的回應,則可以確定埠是開啟的。否則,如果遠端機器傳回RST旗標,則可以說埠是關閉的。
  • sF(TCP FIN 掃描):這是一種傳送包含FIN旗標的TCP封包到目標機器的掃描型別。如果遠端機器傳回回應,則可以確定埠是開啟的。如果遠端機器傳回RST旗標,則可以說埠是關閉的。
  • sX(TCP XMAS 掃描):這是一種傳送包含PSH、FIN或URG旗標的TCP封包到目標機器的掃描型別。如果遠端機器傳回有效的回應,則可以確定埠是開啟的。如果遠端機器傳回RST旗標,則可以說埠是關閉的。如果我們在回應中獲得ICMP型別3的封包,則埠被過濾。

Nmap預設行為與埠狀態

Nmap的預設行為根據執行它的使用者的不同而有所不同,因為允許在掃描期間傳送封包的許可權不同。掃描型別之間的差異在於從目標機器傳回的封包及其避免被安全系統(如防火牆或入侵檢測系統)檢測到的能力。

Nmap將埠分為以下狀態:

  • 開啟:此狀態表示服務正在偵聽此埠上的連線。
  • 關閉:這表示此埠上沒有執行服務。
  • 過濾:這表示沒有收到封包,無法確定狀態。
  • 未過濾:這表示收到了封包,但無法確定狀態。

使用python-nmap進行埠掃描

在本文中,我們將介紹python-nmap模組,用於在Python中進行埠掃描。我們將瞭解python-nmap模組如何使用Nmap工具,以及它如何成為最佳化針對特定目標、網域、網路或IP地址的發現服務任務的非常有用的工具。

python-nmap安裝與使用

您可以從Bitbucket儲存函式庫構建python-nmap: https://bitbucket.org/xael/python-nmap/

最新版本的python-nmap可以從以下網站下載: http://xael.org/pages/python-nmap-en.html

現在,您可以匯入python-nmap模組,以取得nmap版本和此模組中可用的類別。使用以下命令,我們正在呼叫Python直譯器來檢視python-nmap提供的各種方法和函式:

>>> import nmap
>>> namp.__version__
'0.6.1'
>>> dir(nmap)
['ET', 'PortScanner', 'PortScannerAsync', 'PortScannerError',
'PortScannerHostDict', 'PortScannerYield', 'Process', '__author__', 
'__builtins__', '__cached__', '__doc__', '__file__', '__last_modification__', 
'__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 
'convert_nmap_output_to_encoding', 'csv', 'io', 'nmap', 'os', 're', 'shlex', 
'subprocess', 'sys']

驗證模組安裝後,我們可以在特定主機上開始掃描。我們需要例項化PortScanner類別的物件,以便存取scan()方法。

>>> port_scan = nmap.PortScanner()
>>> dir(port_scan)
['_PortScanner__process', '__class__', '__delattr__', '__dict__', '__dir__', 
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', 
'__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', 
'__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'analyse_nmap_xml_scan', 
'command_line', 'csv', 'get_nmap_last_output', 'has_host', 'nmap_version', 'scan', 
'scaninfo', 'scanstats']

內容解密:

  1. import nmap:匯入python-nmap模組,以便在Python中使用Nmap的功能。
  2. nmap.__version__:檢視當前安裝的python-nmap版本。
  3. dir(nmap):列出python-nmap模組中可用的類別、方法和屬性。
  4. port_scan = nmap.PortScanner():建立PortScanner類別的例項,用於執行Nmap掃描。
  5. dir(port_scan):列出PortScanner例項可用的方法和屬性,用於瞭解其功能。

透過使用python-nmap模組,我們可以輕鬆地在Python指令碼中整合Nmap的功能,實作自動化的埠掃描和網路偵察任務。

使用 Nmap 進行埠掃描的介紹

Nmap 是一款強大的網路掃描工具,用於檢測網路中的主機和服務。Python-nmap 是 Nmap 的 Python 封裝函式庫,允許開發者使用 Python 語言呼叫 Nmap 的功能。在本章中,我們將介紹如何使用 python-nmap 進行埠掃描。

PortScanner 類別的屬性和方法

首先,我們需要了解 PortScanner 類別的屬性和方法。我們可以使用 dir() 函式來檢視 PortScanner 物件的屬性和方法:

>>> import nmap
>>> port_scan = nmap.PortScanner()
>>> dir(port_scan)
['__class__', ..., 'scan', 'scaninfo', 'scanstats']

內容解密:

  • dir() 函式傳回一個列表,包含了 PortScanner 物件的所有屬性和方法。
  • 我們可以看到 PortScanner 類別提供了許多有用的方法和屬性,例如 scan()scaninfo()scanstats()

使用 help() 函式,我們可以取得關於 scan() 方法的詳細資訊:

>>> help(port_scan.scan)
Help on method scan in module nmap.nmap:
scan(hosts='127.0.0.1', ports=None, arguments='-sV', sudo=False) method of nmap.nmap.PortScanner instance
    Scan given hosts
    ...

內容解密:

  • help() 函式提供了 scan() 方法的詳細資訊,包括引數和傳回值。
  • scan() 方法接受四個引數:hostsportsargumentssudo
  • hosts 引數指定要掃描的主機,可以是 IP 地址或網域名稱。
  • ports 引數指定要掃描的埠號,可以是單個埠號或埠號範圍。
  • arguments 引數指定 Nmap 的掃描引數,例如 -sV 表示檢測服務版本。

使用 python-nmap 進行埠掃描

現在,讓我們使用 python-nmap 進行埠掃描。首先,我們需要建立一個 PortScanner 物件:

>>> portScanner = nmap.PortScanner()
>>> results = portScanner.scan('scanme.nmap.org', '80-85', '-sV')
>>> results
{'nmap': {'command_line': 'nmap -oX - -p 80-85 -sV scanme.nmap.org', ...}, ...}

內容解密:

  • 我們建立了一個 PortScanner 物件,並呼叫了 scan() 方法對 scanme.nmap.org 進行埠掃描,掃描範圍是 80-85 埠。
  • -sV 引數表示檢測服務版本。
  • results 變數包含了掃描結果,是一個字典。

我們可以使用 command_line() 方法來檢視 Nmap 的命令列:

>>> portScanner.command_line()
'nmap -oX - -p 80-85 -sV scanme.nmap.org'

內容解密:

  • command_line() 方法傳回了 Nmap 的命令列,表示實際執行的 Nmap 命令。

分析掃描結果

掃描結果包含了豐富的資訊,包括主機狀態、埠狀態和服務版本等。我們可以使用 all_hosts() 方法來取得所有主機的列表:

>>> for host in portScanner.all_hosts():
...     print('Host : %s (%s)' % (host, portScanner[host].hostname()))
...     print('State : %s' % portScanner[host].state())
...
Host : 45.33.32.156 (scanme.nmap.org)
State : up

內容解密:

  • all_hosts() 方法傳回了所有主機的列表。
  • 我們遍歷了所有主機,並列印預出了主機的 IP 地址、主機名和狀態。

使用 python-nmap 的不同掃描模式

python-nmap 支援多種掃描模式,包括同步和非同步掃描。在本文中,我們將介紹如何使用 python-nmap 的不同掃描模式。

同步掃描模式

在同步掃描模式下,每次掃描一個埠,需要等待掃描完成後才能進行下一個埠的掃描。

python-nmap 指令碼範例

以下是一個使用 python-nmap 的指令碼範例,用於掃描指定主機的特定埠列表:

#!/usr/bin/env python3
import nmap

portScanner = nmap.PortScanner()
host_scan = input('Host scan: ')
portlist = "21,22,23,25,80"
portScanner.scan(hosts=host_scan, arguments='-n -p' + portlist)

print(portScanner.command_line())

hosts_list = [(x, portScanner[x]['status']['state']) for x in portScanner.all_hosts()]
for host, status in hosts_list:
    print(host, status)
    for protocol in portScanner[host].all_protocols():
        print('Protocol : %s' % protocol)
        listport = portScanner[host]['tcp'].keys()
        for port in listport:
            print('Port : %s State : %s' % (port, portScanner[host][protocol][port]['state']))

內容解密:

  • 該指令碼首先匯入了 nmap 模組,並建立了一個 PortScanner 物件。
  • 使用者輸入要掃描的主機 IP 地址或網域名稱。
  • 指定要掃描的埠列表為 21、22、23、25 和 80。
  • 使用 -n 引數禁止 DNS 解析,並使用 -p 引數指定要掃描的埠列表。
  • 列印出實際執行的 Nmap 命令列。
  • 取得所有主機的列表,並遍歷每個主機,列印預出主機的 IP 地址和狀態。
  • 對每個主機,遍歷每個協定(例如 TCP),並列印預出協定名稱。
  • 對每個協定,取得開放的埠列表,並遍歷每個埠,列印預出埠號和狀態。

執行該指令碼後,我們可以得到類別似以下的輸出結果:

$ python3 Nmap_port_scanner.py
Host scan: scanme.nmap.org
nmap -oX - -n -p21,22,23,25,80 scanme.nmap.org
45.33.32.156 up
Protocol : tcp
Port : 21 State : closed
Port : 22 State : open
Port : 23 State : closed
Port : 25 State : closed
Port : 80 State : open

內容解密:

  • 輸出結果顯示了實際執行的 Nmap 命令列,以及掃描結果。
  • 對每個主機,顯示了其 IP 地址和狀態。
  • 對每個協定,顯示了其名稱和開放的埠列表,以及每個埠的狀態。

使用 python-nmap 進行掃描模式分析

python-nmap 是一個強大的 Python 函式庫,用於進行網路掃描和偵測。透過這個函式庫,我們可以實作多種掃描模式,包括同步和非同步掃描。

同步掃描實作

同步掃描是一種基本的掃描方式,它按照順序對目標主機的特定埠進行掃描。在下面的範例中,我們建立了一個名為 NmapScanner 的類別,該類別允許我們掃描指定的 IP 位址和埠列表。

#!/usr/bin/env python3
import optparse
import nmap

class NmapScanner:
    def __init__(self):
        self.portScanner = nmap.PortScanner()

    def nmapScan(self, ip_address, port):
        self.portScanner.scan(ip_address, port)
        self.state = self.portScanner[ip_address]['tcp'][int(port)]['state']
        print(" [+] Executing command: ", self.portScanner.command_line())
        print(" [+] "+ ip_address + " tcp/" + port + " " + self.state)

def main():
    parser = optparse.OptionParser("usage%prog " + "--ip_address <target ip address> --ports <target port>")
    parser.add_option('--ip_address', dest = 'ip_address', type = 'string', help = 'Please, specify the target ip address.')
    parser.add_option('--ports', dest = 'ports', type = 'string', help = 'Please, specify the target port(s) separated by comma.')
    (options, args) = parser.parse_args()
    if (options.ip_address == None) | (options.ports == None):
        print('[-] You must specify a target ip_address and a target port(s).')
        exit(0)
    ip_address = options.ip_address
    ports = options.ports.split(',')
    for port in ports:
        NmapScanner().nmapScan(ip_address, port)

if __name__ == "__main__":
    main()

內容解密:

  1. NmapScanner 類別初始化:在 __init__ 方法中,我們初始化了一個 nmap.PortScanner() 物件,用於進行埠掃描。
  2. nmapScan 方法:該方法接收 IP 位址和埠號作為引數,使用 portScanner.scan() 方法進行掃描,並取得掃描結果。
  3. 引數解析:在 main 函式中,我們使用 optparse 模組解析命令列引數,包括目標 IP 位址和埠列表。
  4. 迴圈掃描:對埠列表中的每個埠,呼叫 NmapScanner().nmapScan(ip_address, port) 方法進行掃描。

CSV 格式輸出掃描結果

除了將掃描結果輸出到控制檯外,我們還可以將結果以 CSV 格式儲存到檔案中。下面的範例展示瞭如何實作這一點。

#!/usr/bin/env python3
import optparse
import nmap
import csv

class NmapScannerCSV:
    def __init__(self):
        self.portScanner = nmap.PortScanner()

    def nmapScanCSV(self, host, ports):
        try:
            print("Checking ports "+ str(ports) +" ..........")
            self.portScanner.scan(host, arguments='-n -p'+ports)
            print("[*] Executing command: %s" % self.portScanner.command_line())
            print(self.portScanner.csv())
            print("Summary for host",host)
            with open('csv_file.csv', mode='w') as csv_file:
                csv_writer = csv.writer(csv_file, delimiter=',')
                csv_writer.writerow(['Host', 'Protocol', 'Port', 'State'])
                for x in self.portScanner.csv().split("\n")[1:-1]:
                    splited_line = x.split(";")
                    host = splited_line[0]
                    protocol = splited_line[5]
                    port = splited_line[4]
                    state = splited_line[6]
                    print("Protocol:",protocol,"Port:",port,"State:",state)
                    csv_writer.writerow([host, protocol, port, state])
        except Exception as exception:
            print("Error to connect with " + host + " for port scanning" ,exception)

def main():
    parser = optparse.OptionParser("usage%prog " + "--host <target host> --ports <target port>")
    parser.add_option('--host', dest = 'host', type = 'string', help = 'Please, specify the target host.')
    parser.add_option('--ports', dest = 'ports', type = 'string', help = 'Please, specify the target port(s) separated by comma.')
    (options, args) = parser.parse_args()
    if (options.host == None) | (options.ports == None):
        print('[-] You must specify a target host and a target port(s).')
        exit(0)
    host = options.host
    ports = options.ports
    NmapScannerCSV().nmapScanCSV(host,ports)

if __name__ == "__main__":
    main()

內容解密:

  1. NmapScannerCSV 類別:與 NmapScanner 類別似,但增加了將掃描結果輸出到 CSV 檔案的功能。
  2. nmapScanCSV 方法:使用 portScanner.scan() 方法進行掃描,並將結果以 CSV 格式輸出到檔案中。
  3. CSV 寫入:使用 csv.writer 將掃描結果逐行寫入 CSV 檔案中,包括主機、協定、埠號和狀態等資訊。

使用 python-nmap 的非同步掃描模式

非同步掃描模式允許我們同時對不同的埠進行掃描,並定義一個回呼函式,當特定埠的掃描完成時執行。這個功能使得我們能夠更高效地進行網路掃描。