new: arp spoof can usurpate any ip address, ip forwarding can be disabled

This commit is contained in:
pviossat 2021-09-10 15:12:22 +02:00 committed by pviossat
commit 0759ecbc0d
2 changed files with 49 additions and 31 deletions

View file

@ -10,8 +10,6 @@ import (
"github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/network"
"github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/packets"
"github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/session"
"github.com/malfunkt/iprange"
) )
type ArpSpoofer struct { type ArpSpoofer struct {
@ -20,10 +18,12 @@ type ArpSpoofer struct {
macs []net.HardwareAddr macs []net.HardwareAddr
wAddresses []net.IP wAddresses []net.IP
wMacs []net.HardwareAddr wMacs []net.HardwareAddr
uAdresses []net.IP
fullDuplex bool fullDuplex bool
internal bool internal bool
ban bool ban bool
skipRestore bool skipRestore bool
forward bool
waitGroup *sync.WaitGroup waitGroup *sync.WaitGroup
} }
@ -34,10 +34,12 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer {
macs: make([]net.HardwareAddr, 0), macs: make([]net.HardwareAddr, 0),
wAddresses: make([]net.IP, 0), wAddresses: make([]net.IP, 0),
wMacs: make([]net.HardwareAddr, 0), wMacs: make([]net.HardwareAddr, 0),
uAdresses: make([]net.IP, 0),
ban: false, ban: false,
internal: false, internal: false,
fullDuplex: false, fullDuplex: false,
skipRestore: false, skipRestore: false,
forward: true,
waitGroup: &sync.WaitGroup{}, waitGroup: &sync.WaitGroup{},
} }
@ -47,6 +49,8 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer {
mod.AddParam(session.NewStringParameter("arp.spoof.whitelist", "", "", "Comma separated list of IP addresses, MAC addresses or aliases to skip while spoofing.")) mod.AddParam(session.NewStringParameter("arp.spoof.whitelist", "", "", "Comma separated list of IP addresses, MAC addresses or aliases to skip while spoofing."))
mod.AddParam((session.NewStringParameter("arp.spoof.usurpate", session.ParamGatewayAddress, "", "IP addresses to usurpate, also supports nmap style IP ranges.")))
mod.AddParam(session.NewBoolParameter("arp.spoof.internal", mod.AddParam(session.NewBoolParameter("arp.spoof.internal",
"false", "false",
"If true, local connections among computers of the network will be spoofed, otherwise only connections going to and coming from the external network.")) "If true, local connections among computers of the network will be spoofed, otherwise only connections going to and coming from the external network."))
@ -69,6 +73,10 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer {
} }
}) })
mod.AddParam(session.NewBoolParameter("arp.spoof.forwarding",
"true",
"If set to true, IP forwarding will be enabled."))
mod.AddHandler(session.NewModuleHandler("arp.spoof on", "", mod.AddHandler(session.NewModuleHandler("arp.spoof on", "",
"Start ARP spoofer.", "Start ARP spoofer.",
func(args []string) error { func(args []string) error {
@ -113,29 +121,43 @@ func (mod *ArpSpoofer) Configure() error {
var err error var err error
var targets string var targets string
var whitelist string var whitelist string
var uTargets string
if err, mod.fullDuplex = mod.BoolParam("arp.spoof.fullduplex"); err != nil { if err, mod.fullDuplex = mod.BoolParam("arp.spoof.fullduplex"); err != nil {
return err return err
} else if err, mod.internal = mod.BoolParam("arp.spoof.internal"); err != nil { } else if err, mod.internal = mod.BoolParam("arp.spoof.internal"); err != nil {
return err return err
} else if err, mod.forward = mod.BoolParam("arp.spoof.forwarding"); err != nil {
return err
} else if err, targets = mod.StringParam("arp.spoof.targets"); err != nil { } else if err, targets = mod.StringParam("arp.spoof.targets"); err != nil {
return err return err
} else if err, whitelist = mod.StringParam("arp.spoof.whitelist"); err != nil { } else if err, whitelist = mod.StringParam("arp.spoof.whitelist"); err != nil {
return err return err
} else if err, uTargets = mod.StringParam("arp.spoof.usurpate"); err != nil {
return err
} else if mod.addresses, mod.macs, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil { } else if mod.addresses, mod.macs, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil {
return err return err
} else if mod.wAddresses, mod.wMacs, err = network.ParseTargets(whitelist, mod.Session.Lan.Aliases()); err != nil { } else if mod.wAddresses, mod.wMacs, err = network.ParseTargets(whitelist, mod.Session.Lan.Aliases()); err != nil {
return err return err
} else if mod.uAdresses, _, err = network.ParseTargets(uTargets, nil); err != nil {
return err
} }
mod.Debug(" addresses=%v macs=%v whitelisted-addresses=%v whitelisted-macs=%v", mod.addresses, mod.macs, mod.wAddresses, mod.wMacs) mod.Debug(" addresses=%v macs=%v whitelisted-addresses=%v whitelisted-macs=%v usurpate-addresses=%v", mod.addresses, mod.macs, mod.wAddresses, mod.wMacs, mod.uAdresses)
if mod.ban { if mod.ban {
mod.Warning("running in ban mode, forwarding not enabled!") mod.Warning("running in ban mode, forwarding not enabled!")
mod.Session.Firewall.EnableForwarding(false) mod.Session.Firewall.EnableForwarding(false)
} else if !mod.Session.Firewall.IsForwardingEnabled() { } else if mod.forward {
mod.Info("enabling forwarding") mod.Info("enabling forwarding")
mod.Session.Firewall.EnableForwarding(true) if !mod.Session.Firewall.IsForwardingEnabled() {
mod.Session.Firewall.EnableForwarding(true)
}
} else {
mod.Warning("forwarding is disabled")
if mod.Session.Firewall.IsForwardingEnabled() {
mod.Session.Firewall.EnableForwarding(false)
}
} }
return nil return nil
@ -153,17 +175,9 @@ func (mod *ArpSpoofer) Start() error {
} }
return mod.SetRunning(true, func() { return mod.SetRunning(true, func() {
neighbours := []net.IP{} nUsurpate := len(mod.uAdresses)
if mod.internal { mod.Info("arp spoofer started targeting %d addresses, probing %d targets.", nUsurpate, nTargets)
list, _ := iprange.ParseList(mod.Session.Interface.CIDR())
neighbours = list.Expand()
nNeigh := len(neighbours) - 2
mod.Warning("arp spoofer started targeting %d possible network neighbours of %d targets.", nNeigh, nTargets)
} else {
mod.Info("arp spoofer started, probing %d targets.", nTargets)
}
if mod.fullDuplex { if mod.fullDuplex {
mod.Warning("full duplex spoofing enabled, if the router has ARP spoofing mechanisms, the attack will fail.") mod.Warning("full duplex spoofing enabled, if the router has ARP spoofing mechanisms, the attack will fail.")
@ -172,12 +186,10 @@ func (mod *ArpSpoofer) Start() error {
mod.waitGroup.Add(1) mod.waitGroup.Add(1)
defer mod.waitGroup.Done() defer mod.waitGroup.Done()
gwIP := mod.Session.Gateway.IP
myMAC := mod.Session.Interface.HW myMAC := mod.Session.Interface.HW
for mod.Running() { for mod.Running() {
mod.arpSpoofTargets(gwIP, myMAC, true, false) for _, address := range mod.uAdresses {
for _, address := range neighbours { if net.IP.Equal(address, mod.Session.Gateway.IP) || !mod.Session.Skip(address) {
if !mod.Session.Skip(address) {
mod.arpSpoofTargets(address, myMAC, true, false) mod.arpSpoofTargets(address, myMAC, true, false)
} }
} }
@ -191,16 +203,13 @@ func (mod *ArpSpoofer) unSpoof() error {
if !mod.skipRestore { if !mod.skipRestore {
nTargets := len(mod.addresses) + len(mod.macs) nTargets := len(mod.addresses) + len(mod.macs)
mod.Info("restoring ARP cache of %d targets.", nTargets) mod.Info("restoring ARP cache of %d targets.", nTargets)
mod.arpSpoofTargets(mod.Session.Gateway.IP, mod.Session.Gateway.HW, false, false)
if mod.internal { for _, address := range mod.uAdresses {
list, _ := iprange.ParseList(mod.Session.Interface.CIDR()) if net.IP.Equal(address, mod.Session.Gateway.IP) || !mod.Session.Skip(address) {
neighbours := list.Expand() if realMAC, err := mod.Session.FindMAC(address, false); err == nil {
for _, address := range neighbours { mod.arpSpoofTargets(address, realMAC, false, false)
if !mod.Session.Skip(address) { } else {
if realMAC, err := mod.Session.FindMAC(address, false); err == nil { mod.Warning("cannot find mac address for %s, cannot restore", address.String())
mod.arpSpoofTargets(address, realMAC, false, false)
}
} }
} }
} }
@ -294,6 +303,12 @@ func (mod *ArpSpoofer) arpSpoofTargets(saddr net.IP, smac net.HardwareAddr, chec
continue continue
} }
if bytes.Equal(smac, ourHW) {
mod.Debug("telling %s (%s) we are %s", ip, mac, saddr.String())
} else {
mod.Debug("telling %s (%s) %s is %s", ip, mac, smac, saddr.String())
}
rawIP := net.ParseIP(ip) rawIP := net.ParseIP(ip)
if err, pkt := packets.NewARPReply(saddr, smac, rawIP, mac); err != nil { if err, pkt := packets.NewARPReply(saddr, smac, rawIP, mac); err != nil {
mod.Error("error while creating ARP spoof packet for %s: %s", ip, err) mod.Error("error while creating ARP spoof packet for %s: %s", ip, err)
@ -308,7 +323,7 @@ func (mod *ArpSpoofer) arpSpoofTargets(saddr net.IP, smac net.HardwareAddr, chec
if isSpoofing { if isSpoofing {
mod.Debug("telling the gw we are %s", ip) mod.Debug("telling the gw we are %s", ip)
// we told the target we're te gateway, not let's tell the // we told the target we're the gateway, now let's tell the
// gateway that we are the target // gateway that we are the target
if err, gwPacket = packets.NewARPReply(rawIP, ourHW, gwIP, gwHW); err != nil { if err, gwPacket = packets.NewARPReply(rawIP, ourHW, gwIP, gwHW); err != nil {
mod.Error("error while creating ARP spoof packet: %s", err) mod.Error("error while creating ARP spoof packet: %s", err)

View file

@ -98,6 +98,7 @@ const ParamIfaceAddress6 = "<interface address6>"
const ParamIfaceMac = "<interface mac>" const ParamIfaceMac = "<interface mac>"
const ParamSubnet = "<entire subnet>" const ParamSubnet = "<entire subnet>"
const ParamRandomMAC = "<random mac>" const ParamRandomMAC = "<random mac>"
const ParamGatewayAddress = "<gateway address>"
var ParamIfaceNameParser = regexp.MustCompile("<([a-zA-Z0-9]{2,16})>") var ParamIfaceNameParser = regexp.MustCompile("<([a-zA-Z0-9]{2,16})>")
@ -117,10 +118,12 @@ func (p ModuleParam) parse(s *Session, v string) string {
hw := make([]byte, 6) hw := make([]byte, 6)
rand.Read(hw) rand.Read(hw)
v = net.HardwareAddr(hw).String() v = net.HardwareAddr(hw).String()
case ParamGatewayAddress:
v = s.Gateway.IpAddress
default: default:
// check the <iface> case // check the <iface> case
if m := ParamIfaceNameParser.FindStringSubmatch(v); len(m) == 2 { if m := ParamIfaceNameParser.FindStringSubmatch(v); len(m) == 2 {
// does it match any interface? // does it match any interface?
name := m[1] name := m[1]
if iface, err := net.InterfaceByName(name); err == nil { if iface, err := net.InterfaceByName(name); err == nil {
if addrs, err := iface.Addrs(); err == nil { if addrs, err := iface.Addrs(); err == nil {