mirror of
https://github.com/bettercap/bettercap
synced 2025-08-19 13:09:49 -07:00
new: arp spoof can usurpate any ip address, ip forwarding can be disabled
This commit is contained in:
parent
ee35550f70
commit
0759ecbc0d
2 changed files with 49 additions and 31 deletions
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue