Network Scanner(一):使用 Python 撰寫網路掃描器

Note: 此教學可應用在大部分的 Linux 作業系統。

什麼是網路掃描器(Network Scanner)?

網路掃描器(Network Scanner)是一種軟件工具,可以在網路中掃描連接的設備。它還用於診斷(Diagnostic)和調查(Investigative )目的,用來查找和分類網絡上正在運行的設備。該工具將一個 IP 地址或一系列 IP 地址作為輸入,然後依序掃描每個 IP 地址,並確定該特定 IP 地址上是否存在設備。它會掃描網路並返回 IP 地址(IP Address)和相應的 MAC 地址(MAC Addrerss)。用的網絡安全(CyberSecurity )專業人員常用的一種流行工具是 nmap


如何運作?

位址解析協定(Address Resolution Protocol)

要了解網路掃描器如何掃描整個網路,我們首先需要了解什麼是位址解析協定Address Resolution Protocol,縮寫:ARP),它是一個通過解析網路層位址來找尋資料鏈路層位址的網路傳輸協定。

在乙太網路協定中規定,同一區域網路中的一台主機要和另一台主機進行直接通信,必須要知道目標主機的 MAC 位址。而在 TCP/IP 協定中,網路層和傳輸層只關心目標主機的 IP 位址。這就導致在乙太網路中使用 IP 協定時,資料鏈路層的乙太網路協定接到上層 IP 協定提供的資料中,只包含目的主機的 IP 位址。於是需要一種方法,根據目的主機的 IP 位址,獲得其 MAC 位址。這就是 ARP 協定要做的事情。所謂位址解析(Address Resolution)就是主機在傳送影格(Frame)前將目標 IP 位址轉換成目標 MAC 位址的過程。


原理

在每台安裝有 TCP/IP 協定的電腦或路由器裡都有一個 ARP 快取表,表里的 IP 位址與 MAC位址 是一對應的,如下表所示。

主機名稱IP位址MAC位址
A192.168.38.1000-AA-00-62-D2-02
B192.168.38.1100-BB-00-62-C2-02
C192.168.38.1200-CC-00-62-C2-02
D192.168.38.1300-DD-00-62-C2-02

以主機 A(192.168.38.10)向主機 B(192.168.38.11)傳送資料為例。

  1. 當傳送資料時,主機 A 會在自己的 ARP 快取表中尋找是否有目標 IP 位址。如果找到就知道目標 MAC 位址為(00-BB-00-62-C2-02),直接把目標 MAC 位址寫入影格裡面傳送就可。
  2. 如果在 ARP 快取表中沒有找到相對應的 IP 位址,主機 A 就會在網路上傳送一個廣播(ARP Request),目標 MAC 位址是「FF:FF:FF:FF:FF:FF」,這表示向同一網段內的所有主機發出這樣的詢問:「192.168.38.11 的 MAC 位址是什麼?」
  3. 網路上其他主機並不回應 ARP 詢問,只有主機 B 接收到這個影格時,才向主機 A 做出這樣的回應(ARP Response):「192.168.38.11 的 MAC 位址是 00-BB-00-62-C2-02」,此回應以單播方式。這樣,主機 A 就知道主機 B 的 MAC 位址,它就可以向主機 B 傳送資訊。同時它還更新自己的 ARP 高速緩衝記憶體(ARP Cache),下次再向主機 B 傳送資訊時,直接從 ARP 快取表里尋找就可。

網路掃描器使用 ARP 請求(Request)和響應(Response)來掃描整個網路,以查找網絡上的活動設備並找到其 MAC 位址。


使用 Python 撰寫網路掃描器

開發環境

使用模組(Python 模組)

實作

以下為完整程式碼:

Note: 10.0.2.1/24 means IP Addresses from 10.0.2.1 to 10.0.2.254

由上面程式碼可知,在 scan(ip) 函式中,我們要做的第一件事是創建一個 ARP 請求:

arp_request = scapy.ARP(pdst=ip)

上面片段的程式碼使用 scapy 的 ARP 類別創建了 ARP 請求幀(ARP Request Frame),並提供了目標 IP 地址(pdst)作為該函數的參數。我們要將 ARP 請求幀指向到所需的 IP 地址。例如,如果 psdt =”10.0.2.15″,則 ARP 請求僅針對該 IP 地址。

到目前為止,可能會有個疑問,我們該如何知道 scapy 的 ARP 類別中包含哪些變量(Variable)。我們可以使用 scapy.ls() 函式來取得資訊:

!/usr/bin/env python
import scapy.all as scapy
print(scapy.ls(scapy.ARP()))

OUTPUT
hwtype : XShortField        = 1               (1)
ptype  : XShortEnumField    = 2048            (2048)
hwlen  : FieldLenField      = None            (None)
plen   : FieldLenField      = None            (None)
op     : ShortEnumField     = 1               (1)
hwsrc  : MultipleTypeField  = '08:00:27:62:a1:c8' (None)
psrc   : MultipleTypeField  = '10.0.2.8'      (None)
hwdst  : MultipleTypeField  = '00:00:00:00:00:00' (None)
pdst   : MultipleTypeField  = '0.0.0.0'       (None)

上變有幾個主要變量我們需要了解:

  • hwsrc = 來源 MAC 位址
  • psrc = 來源 IP 地址
  • hwdst = 目標 MAC 位址
  • pdst = 目標 IP 地址

在我們的例子中,我的 Kali 機器的 IP 地址為 “10.0.2.8”,MAC地址為 “08:00:27:62:a1:c8″,因此 psrc 和 hwsrc 字段中預設為這些值。而 hwdst 和 pdst 的默認值分別為 “00:00:00:00:00:00” 和 “0.0.0.0”。

前面我們創建了 ARP 請求幀,接下來我們需要創建一個以太幀(Ethernet Frame)。在以太網鏈路上的數據包稱作以太幀。以太幀起始部分由前導碼和幀開始符組成。後面緊跟著一個以太網報頭,以 MAC 地址說明目的地址和源地址。幀的中部是該幀負載的包含其他協議報頭的數據包(例如 IP 協議)。以太幀由一個32位冗餘校驗碼結尾。它用於檢驗數據傳輸是否出現損壞。以太幀詳細可閱讀次篇文章

ARP 請求應該被廣播(傳輸到網絡中的每個 IP 地址)。因此,為了廣播 ARP 請求,我們需要將”以太網”的目標地址欄位設置為 “FF:FF:FF:FF:FF:FF”,這表示向同一網段內的所有主機發出詢問。現在,我們使用 Scapy 進行此操作。

broadcast = scapy.Ether(dst="ff:ff:ff:ff:ff:ff")

下一步是結合 ARP 請求和以太幀。我們使用 Scapy 進行此操作,因為它提供了一種非常方便的組合框架的方法。我們通過以下程式碼來實現,通過使用 ‘/’ 號組合 ARP 請求和以太幀來創建一個新的幀。

arp_request_broadcast = broadcast/arp_request

現在剩下的唯一事情就是發送組合的幀並接收響應。我們將 arp_request_broadcast(我們的最終的組合幀)傳遞給下面的函數 scapy.srp()

answered_list = scapy.srp(arp_request_broadcast, timeout=1, verbose=False)[0]

最終我們將上述返回的結果列印出來並運行可以得到下面結果

程式連結:Github


相關文章

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *