diff --git a/modules/dns_spoof/dns_spoof.go b/modules/dns_spoof/dns_spoof.go index f4d5c9ce..6905ff75 100644 --- a/modules/dns_spoof/dns_spoof.go +++ b/modules/dns_spoof/dns_spoof.go @@ -5,10 +5,6 @@ import ( "fmt" "net" "sync" - "context" - "bufio" - "os" - "regexp" "github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/session" @@ -25,9 +21,6 @@ type DNSSpoofer struct { Handle *pcap.Handle Hosts Hosts All bool - ProxyDNS bool - ProxyDNSIP net.IP - ProxyResolver *net.Resolver waitGroup *sync.WaitGroup pktSourceChan chan gopacket.Packet } @@ -37,9 +30,6 @@ func NewDNSSpoofer(s *session.Session) *DNSSpoofer { SessionModule: session.NewSessionModule("dns.spoof", s), Handle: nil, All: false, - ProxyDNS: false, - ProxyDNSIP: nil, - ProxyResolver: nil, Hosts: Hosts{}, waitGroup: &sync.WaitGroup{}, } @@ -63,15 +53,6 @@ func NewDNSSpoofer(s *session.Session) *DNSSpoofer { "false", "If true the module will reply to every DNS request, otherwise it will only reply to the one targeting the local pc.")) - mod.AddParam(session.NewBoolParameter("dns.spoof.proxy", - "false", - "If true the module will reply to every DNS request, with faked entries for selected domains and real ones for non-selected domains.")) - - mod.AddParam(session.NewStringParameter("dns.spoof.proxy.srv", - "system", - "", - "IP address of proxy dns server or 'system' for system dns")) - mod.AddHandler(session.NewModuleHandler("dns.spoof on", "", "Start the DNS spoofer in the background.", func(args []string) error { @@ -99,44 +80,17 @@ func (mod DNSSpoofer) Author() string { return "Simone Margaritelli " } -func (mod *DNSSpoofer)getSystemResolver() (net.IP,error) { - file, err := os.Open("/etc/resolv.conf") - if err != nil { - return nil,err - } - defer file.Close() - - scanner := bufio.NewScanner(file) - r := regexp.MustCompile(`^\s*nameserver\s*(?P\d+\.\d+\.\d+\.\d+)`) - for scanner.Scan() { - matches := r.FindStringSubmatch(scanner.Text()) - if len(matches) == 2 { - ip := net.ParseIP(matches[1]) - if ip != nil { - mod.Info("using system dns server for proxy dns: %s",matches[1]) - return ip,nil - } - } - } - - if err := scanner.Err(); err != nil { - return nil,err - } - return nil,fmt.Errorf("no nameserver found for proxy dns") -} - func (mod *DNSSpoofer) Configure() error { var err error var hostsFile string var domains []string var address net.IP - var proxyip string if mod.Running() { return session.ErrAlreadyStarted } else if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { return err - } else if err = mod.Handle.SetBPFFilter("udp and port 53"); err != nil { + } else if err = mod.Handle.SetBPFFilter("udp"); err != nil { return err } else if err, mod.All = mod.BoolParam("dns.spoof.all"); err != nil { return err @@ -146,10 +100,6 @@ func (mod *DNSSpoofer) Configure() error { return err } else if err, hostsFile = mod.StringParam("dns.spoof.hosts"); err != nil { return err - } else if err, mod.ProxyDNS = mod.BoolParam("dns.spoof.proxy"); err != nil { - return err - } else if err, proxyip = mod.StringParam("dns.spoof.proxy.srv"); err != nil { - return err } mod.Hosts = Hosts{} @@ -174,33 +124,6 @@ func (mod *DNSSpoofer) Configure() error { mod.Info("%s -> %s", entry.Host, entry.Address) } - if mod.ProxyDNS { - if proxyip == "system" { - if mod.ProxyDNSIP, err = mod.getSystemResolver(); err != nil { - return err - } - } else { - mod.ProxyDNSIP = net.ParseIP(proxyip) - if mod.ProxyDNSIP == nil { - return fmt.Errorf("invalid dns server ip %s",proxyip) - } - } - - dailer := func(ctx context.Context, network, address string) (net.Conn, error) { - d := net.Dialer{} - return d.DialContext(ctx, "udp", proxyip + ":53") - } - - mod.ProxyResolver = &net.Resolver{ - Dial: dailer, - PreferGo: true, - } - - if mod.ProxyResolver == nil { - return fmt.Errorf("dns.spoof.proxy.srv must be filled with dns server ip or 'system'") - } - } - if !mod.Session.Firewall.IsForwardingEnabled() { mod.Info("enabling forwarding.") mod.Session.Firewall.EnableForwarding(true) @@ -209,110 +132,48 @@ func (mod *DNSSpoofer) Configure() error { return nil } -func (mod *DNSSpoofer) dnsSend(eth *layers.Ethernet, src net.IP, dst net.IP, udp *layers.UDP, dns *layers.DNS) { - var err error = nil - var raw []byte - - if len(src) == net.IPv4len { - ip4 := layers.IPv4{ - Protocol: layers.IPProtocolUDP, - Version: 4, - TTL: 64, - SrcIP: src, - DstIP: dst, - } - udp.SetNetworkLayerForChecksum(&ip4) - err, raw = packets.Serialize(eth, &ip4, udp, dns) - } else if len(src) == net.IPv6len { - ip6 := layers.IPv6{ - Version: 6, - NextHeader: layers.IPProtocolUDP, - HopLimit: 64, - SrcIP: src, - DstIP: dst, - } - udp.SetNetworkLayerForChecksum(&ip6) - err, raw = packets.Serialize(eth, &ip6, udp, dns) - } else { - mod.Error("invalid protocol for dns proxy.") - } - if err != nil { - mod.Error("error serializing packet: %s.", err) - return - } - - mod.Debug("sending %d bytes of packet ...", len(raw)) - if err := mod.Session.Queue.Send(raw); err != nil { - mod.Error("error sending packet: %s", err) - } -} - -func (mod *DNSSpoofer) generateGenericLayers(pkt gopacket.Packet, peth *layers.Ethernet, pudp *layers.UDP, target net.HardwareAddr)(eth *layers.Ethernet, src net.IP, dst net.IP, udp *layers.UDP, err error) { - nlayer := pkt.NetworkLayer() - if nlayer == nil { - return nil,nil,nil,nil,fmt.Errorf("missing network layer skipping packet.") - } - - var eType layers.EthernetType - if nlayer.LayerType() == layers.LayerTypeIPv4 { - pip := pkt.Layer(layers.LayerTypeIPv4).(*layers.IPv4) - src = pip.DstIP - dst = pip.SrcIP - eType = layers.EthernetTypeIPv4 - - } else { - pip := pkt.Layer(layers.LayerTypeIPv6).(*layers.IPv6) - src = pip.DstIP - dst = pip.SrcIP - eType = layers.EthernetTypeIPv6 - } - - eth = &layers.Ethernet{ - SrcMAC: peth.DstMAC, - DstMAC: target, - EthernetType: eType, - } - - udp = &layers.UDP{ - SrcPort: pudp.DstPort, - DstPort: pudp.SrcPort, - } - - return eth,src,dst,udp,nil -} - -func (mod *DNSSpoofer) dnsNXDomain(pkt gopacket.Packet, peth *layers.Ethernet, pudp *layers.UDP, req *layers.DNS, target net.HardwareAddr) { - - eth, src, dst, udp, err := mod.generateGenericLayers(pkt, peth, pudp, target) - if err != nil { - mod.Debug("%s",err) - } - - dns := &layers.DNS{ - ID: req.ID, - QR: true, - OpCode: layers.DNSOpCodeQuery, - ResponseCode: layers.DNSResponseCodeNXDomain, - QDCount: req.QDCount, - Questions: req.Questions, - } - - mod.dnsSend(eth, src, dst, udp, dns) -} - -func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp *layers.UDP, domain string, address net.IP, req *layers.DNS, target net.HardwareAddr) { redir := fmt.Sprintf("(->%s)", address.String()) +func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp *layers.UDP, domain string, address net.IP, req *layers.DNS, target net.HardwareAddr) { + redir := fmt.Sprintf("(->%s)", address.String()) who := target.String() if t, found := mod.Session.Lan.Get(target.String()); found { who = t.String() } - eth, src, dst, udp, err := mod.generateGenericLayers(pkt, peth, pudp, target) - if err != nil { - mod.Debug("%s",err) + mod.Info("sending spoofed DNS reply for %s %s to %s.", tui.Red(domain), tui.Dim(redir), tui.Bold(who)) + + var err error + var src, dst net.IP + + nlayer := pkt.NetworkLayer() + if nlayer == nil { + mod.Debug("missing network layer skipping packet.") + return } - mod.Info("sending spoofed DNS reply for %s %s to %s.", tui.Red(domain), tui.Dim(redir), tui.Bold(who)) + var eType layers.EthernetType + var ipv6 bool + + if nlayer.LayerType() == layers.LayerTypeIPv4 { + pip := pkt.Layer(layers.LayerTypeIPv4).(*layers.IPv4) + src = pip.DstIP + dst = pip.SrcIP + ipv6 = false + eType = layers.EthernetTypeIPv4 + + } else { + pip := pkt.Layer(layers.LayerTypeIPv6).(*layers.IPv6) + src = pip.DstIP + dst = pip.SrcIP + ipv6 = true + eType = layers.EthernetTypeIPv6 + } + + eth := layers.Ethernet{ + SrcMAC: peth.DstMAC, + DstMAC: target, + EthernetType: eType, + } answers := make([]layers.DNSResourceRecord, 0) for _, q := range req.Questions { @@ -326,7 +187,7 @@ func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp }) } - dns := &layers.DNS{ + dns := layers.DNS{ ID: req.ID, QR: true, OpCode: layers.DNSOpCodeQuery, @@ -335,10 +196,56 @@ func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp Answers: answers, } - mod.dnsSend(eth, src, dst, udp, dns) -} + var raw []byte -func (mod *DNSSpoofer) proxyPacket() { + if ipv6 { + ip6 := layers.IPv6{ + Version: 6, + NextHeader: layers.IPProtocolUDP, + HopLimit: 64, + SrcIP: src, + DstIP: dst, + } + + udp := layers.UDP{ + SrcPort: pudp.DstPort, + DstPort: pudp.SrcPort, + } + + udp.SetNetworkLayerForChecksum(&ip6) + + err, raw = packets.Serialize(ð, &ip6, &udp, &dns) + if err != nil { + mod.Error("error serializing packet: %s.", err) + return + } + } else { + ip4 := layers.IPv4{ + Protocol: layers.IPProtocolUDP, + Version: 4, + TTL: 64, + SrcIP: src, + DstIP: dst, + } + + udp := layers.UDP{ + SrcPort: pudp.DstPort, + DstPort: pudp.SrcPort, + } + + udp.SetNetworkLayerForChecksum(&ip4) + + err, raw = packets.Serialize(ð, &ip4, &udp, &dns) + if err != nil { + mod.Error("error serializing packet: %s.", err) + return + } + } + + mod.Debug("sending %d bytes of packet ...", len(raw)) + if err := mod.Session.Queue.Send(raw); err != nil { + mod.Error("error sending packet: %s", err) + } } func (mod *DNSSpoofer) onPacket(pkt gopacket.Packet) { @@ -347,77 +254,22 @@ func (mod *DNSSpoofer) onPacket(pkt gopacket.Packet) { if typeEth == nil || typeUDP == nil { return } + eth := typeEth.(*layers.Ethernet) - - var sip net.IP = nil - var dip net.IP = nil - srcip := "n/a" - destip := "n/a" - - if mod.ProxyDNS { - if eth.NextLayerType() == layers.LayerTypeIPv4 { - pip := pkt.Layer(layers.LayerTypeIPv4).(*layers.IPv4) - sip = pip.SrcIP - dip = pip.DstIP - } else if eth.NextLayerType() == layers.LayerTypeIPv6 { - pip := pkt.Layer(layers.LayerTypeIPv6).(*layers.IPv6) - sip = pip.DstIP - dip = pip.SrcIP - } else { - mod.Debug("skip invalid ip protocol: %s",eth.NextLayerType()) - return - } - if sip != nil { - srcip = sip.String() - } - if dip != nil { - destip = dip.String() - } - if sip != nil && sip.Equal(mod.ProxyDNSIP) && dip != nil && mod.Session.Interface.IP.Equal(dip) { - mod.Debug("dns.spoof.proxyDNS skipping dns proxy-answer (from server) %s => %s", srcip, destip) - return - } - if sip != nil && mod.Session.Interface.IP.Equal(sip) && dip != nil && dip.Equal(mod.ProxyDNSIP) { - mod.Debug("dns.spoof.proxyDNS skipping dns proxy-request (to server) %s => %s", srcip, destip) - return - } - if sip != nil && mod.Session.Interface.IP.Equal(sip) { - mod.Debug("dns.spoof.proxyDNS skipping dns proxy-answer (to client) %s => %s", srcip, destip) - return - } - } else if !mod.All && !bytes.Equal(eth.DstMAC, mod.Session.Interface.HW) { - mod.Debug("!dns.spoof.All => deny non-local") - return - } - - dns, parsed := pkt.Layer(layers.LayerTypeDNS).(*layers.DNS) - if !parsed || dns.OpCode != layers.DNSOpCodeQuery || len(dns.Questions) == 0 || len(dns.Answers) > 0 { - mod.Debug("blackholing dns answer: %s => %s", srcip, destip) - return - } - - udp := typeUDP.(*layers.UDP) - for _, q := range dns.Questions { - qName := string(q.Name) - if address := mod.Hosts.Resolve(qName); address != nil { - mod.Debug("replying dns query by host lookup %s: %s => %s", qName, srcip, destip ) - mod.dnsReply(pkt, eth, udp, qName, address, dns, eth.SrcMAC) - break - } else if mod.ProxyDNS { - mod.Debug("proxying dns query %s: %s => %s", qName, srcip, destip ) - addr, err := net.LookupHost(qName) - if err != nil || len(addr) == 0 { - mod.Debug("replying dns query by nxdomain %s: %s => %s", qName, srcip, destip ) - mod.dnsNXDomain(pkt, eth, udp, dns, eth.SrcMAC) - break - } else { - mod.Debug("replying dns query by proxy lookup %s: %s => %s", qName, srcip, destip ) - mod.dnsReply(pkt, eth, udp, qName, net.ParseIP(addr[0]), dns, eth.SrcMAC) - break - } - } else { - mod.Debug("skipping domain %s", string(q.Name)) - } + if mod.All || bytes.Equal(eth.DstMAC, mod.Session.Interface.HW) { + dns, parsed := pkt.Layer(layers.LayerTypeDNS).(*layers.DNS) + if parsed && dns.OpCode == layers.DNSOpCodeQuery && len(dns.Questions) > 0 && len(dns.Answers) == 0 { + udp := typeUDP.(*layers.UDP) + for _, q := range dns.Questions { + qName := string(q.Name) + if address := mod.Hosts.Resolve(qName); address != nil { + mod.dnsReply(pkt, eth, udp, qName, address, dns, eth.SrcMAC) + break + } else { + mod.Debug("skipping domain %s", qName) + } + } + } } }