Skip to content

Instantly share code, notes, and snippets.

@003random
Created September 11, 2021 00:33
Show Gist options
  • Select an option

  • Save 003random/7a545253fc2f65e0c3cf0e5d0e5e48e7 to your computer and use it in GitHub Desktop.

Select an option

Save 003random/7a545253fc2f65e0c3cf0e5d0e5e48e7 to your computer and use it in GitHub Desktop.

Revisions

  1. 003random created this gist Sep 11, 2021.
    95 changes: 95 additions & 0 deletions arpspoof-detect.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,95 @@
    package main

    import (
    "fmt"
    "log"
    "net"
    "os"
    "time"

    "github.com/google/gopacket"
    "github.com/google/gopacket/layers"
    "github.com/google/gopacket/pcap"
    )

    func main() {
    // Store arguments as variables of the right type
    iface := os.Args[1]

    srcMAC, err := net.ParseMAC(os.Args[2])
    if err != nil {
    log.Fatal(err)
    }
    srcIP := net.ParseIP(os.Args[3])

    // Create mapping to store ARP reply values
    replies := make(map[string]string)

    // Open socket
    handle, err := pcap.OpenLive(iface, 2048, false, 100*time.Nanosecond)
    if err != nil {
    log.Fatal(err)
    }

    // Only capture ARP replies
    if err := handle.SetBPFFilter("arp[6:2] = 2"); err != nil {
    log.Fatal(err)
    }
    packetSource := gopacket.NewPacketSource(handle, handle.LinkType())

    // Loop over the incoming packets channel
    for packet := range packetSource.Packets() {
    arpLayer := packet.Layer(layers.LayerTypeARP)
    arp, ok := arpLayer.(*layers.ARP)
    if !ok {
    continue
    }

    err = sendARPRequest(handle, srcMAC, srcIP, arp.SourceProtAddress)
    if err != nil {
    log.Fatal(err)
    }

    if previousMAC, ok := replies[net.IP(arp.SourceProtAddress).String()]; ok {
    if previousMAC != net.HardwareAddr(arp.SourceHwAddress).String() {
    fmt.Println("ARP Spoofing Detected for IP Address", net.IP(arp.SourceProtAddress).String())
    }
    }

    replies[net.IP(arp.SourceProtAddress).String()] = net.HardwareAddr(arp.SourceHwAddress).String()
    time.AfterFunc(time.Second*50, func() {
    delete(replies, net.IP(arp.SourceProtAddress).String())
    })

    }
    }

    func sendARPRequest(handle *pcap.Handle, srcMAC net.HardwareAddr, srcIP, dstIP net.IP) error {
    // Construct layers for the ARP request
    eth := layers.Ethernet{
    SrcMAC: srcMAC,
    DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
    EthernetType: layers.EthernetTypeARP,
    }
    arp := layers.ARP{
    AddrType: layers.LinkTypeEthernet,
    Protocol: layers.EthernetTypeIPv4,
    HwAddressSize: 6,
    ProtAddressSize: 4,
    Operation: layers.ARPRequest,
    SourceHwAddress: []byte(srcMAC),
    SourceProtAddress: srcIP.To4(),
    DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
    DstProtAddress: dstIP.To4(),
    }

    buf := gopacket.NewSerializeBuffer()

    // Send a single ARP request packet (we never retry a send, since this
    err := gopacket.SerializeLayers(buf, gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}, &eth, &arp)
    if err != nil {
    return err
    }

    return handle.WritePacketData(buf.Bytes())
    }