// Used https://github.com/miekg/exdns/reflect as a template // // This is an authoritative DNS server that behaves as follows. // If the looked up host is v4-1-1-1-1.v6-2-2-2-2.crazysh.com: // // a. 1.1.1.1 is always returned as the A record // b. The IPv4 embedded IPv6 ::ffff:2.2.2.2 is returned as the AAAA record // // This strange behavior was required for an SSRF exploit to work and might // be useful for testing // // You may find stuff like this useful! // // cruoho@omgwtfbbq ~ % host v4-1-1-1-1.v6-169-254-169-254.crazysh.com // v4-1-1-1-1.v6-169-254-169-254.crazysh.com has address 1.1.1.1 // v4-1-1-1-1.v6-169-254-169-254.crazysh.com has IPv6 address ::ffff:169.254.169.254 // // Multiple records can be returned, e.g. // // v4-1-1-1-1.v4-169-254-169-254.crazysh.com // // if you're in the mood for other dns tricks // // You can also insert meaningless keys in a middle octet if you're watching your // logs and want to tag a specific request, eg v4-1-1-1-1.foo.crazysh.com // // Contact: clint@wtfismyip.com package main import ( "flag" "fmt" "log" "net" "os" "os/signal" "runtime" "runtime/pprof" "strconv" "strings" "syscall" "time" "github.com/miekg/dns" ) var ( cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") printf = flag.Bool("print", false, "print replies") compress = flag.Bool("compress", false, "compress replies") tsig = flag.String("tsig", "", "use MD5 hmac tsig: keyname:base64") soreuseport = flag.Int("soreuseport", 0, "use SO_REUSE_PORT") cpu = flag.Int("cpu", 0, "number of cpu to use") ) const dom = "crazysh.com." const ns1 = "arf1.crazysh.com." const ns2 = "arf2.crazysh.com." func handleReflect(w dns.ResponseWriter, r *dns.Msg) { var ( rr dns.RR rr2 dns.RR str string remoteIP string ) m := new(dns.Msg) // Get the hostname in the DNS request Question := r.Question[0] Name := strings.ToLower(Question.Name) // nuke uvpn.me and trailing dot Host := strings.TrimSuffix(strings.Split(Name, dom)[0], ".") Host = strings.ToLower(Host) Hosts := strings.Split(Host, ".") host4 := make([]string, 0, 20) host6 := make([]string, 0, 20) rr4 := make([]dns.RR, 0, 20) rr6 := make([]dns.RR, 0, 20) var ttl uint32 = 1 for i := 0; i < len(Hosts); i++ { if strings.HasPrefix(Hosts[i], "v4-") || (strings.HasPrefix(Hosts[i], "V4-")) { host4 = append(host4, strings.ReplaceAll(strings.TrimPrefix(strings.TrimPrefix(Hosts[i], "v4-"), "V4-"), "-", ".")) } else if strings.HasPrefix(Hosts[i], "v6-") || (strings.HasPrefix(Hosts[i], "V6-")) { host6 = append(host6, ("::ffff:" + strings.ReplaceAll(strings.TrimPrefix(strings.TrimPrefix(Hosts[i], "v6-"), "V6-"), "-", "."))) } else if Host == "arf1" { host4 = append(host4, "54.39.106.25") host6 = append(host6, "2607:5300:203:3c19::2") ttl = 3600 } else if Host == "arf2" { host4 = append(host4, "54.39.106.25") host6 = append(host6, "2607:5300:203:3c19::2") ttl = 3600 } else if Host == "" { host4 = append(host4, "51.222.11.82") ttl = 3600 } } m.SetReply(r) m.Authoritative = true m.Compress = *compress if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok { str = "Port: " + strconv.Itoa(ip.Port) + " (udp)" remoteIP, _, _ = net.SplitHostPort(ip.String()) } if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok { str = "Port: " + strconv.Itoa(ip.Port) + " (tcp)" remoteIP, _, _ = net.SplitHostPort(ip.String()) } now := time.Now() fmt.Printf("%s %s: %s\n", remoteIP, now, Name) // create the A and AAAA records for i := 0; i < len(host6); i++ { rr = &dns.AAAA{ Hdr: dns.RR_Header{Name: Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}, AAAA: net.ParseIP(host6[i]), } rr6 = append(rr6, rr) } for j := 0; j < len(host4); j++ { rr2 = &dns.A{ Hdr: dns.RR_Header{Name: Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}, A: net.ParseIP(host4[j]), } rr4 = append(rr4, rr2) } t := &dns.TXT{ Hdr: dns.RR_Header{Name: Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: ttl}, Txt: []string{str}, } ns1 := &dns.NS{ Hdr: dns.RR_Header{Name: Name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 86400}, Ns: dns.Fqdn(ns1), } ns2 := &dns.NS{ Hdr: dns.RR_Header{Name: Name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 86400}, Ns: dns.Fqdn(ns2), } soa := &dns.SOA{ Hdr: dns.RR_Header{Name: Name, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 86400}, Ns: "arf1.crazysh.com.", Mbox: "admin.crazysh.com.", Serial: 1, Refresh: 1200, Retry: 600, Expire: 1209600, Minttl: 3600, } switch r.Question[0].Qtype { // serve responses case dns.TypeTXT: m.Answer = append(m.Answer, t) //m.Extra = append(m.Extra, rr) default: fallthrough case dns.TypeA: for i := 0; i < len(rr4); i++ { m.Answer = append(m.Answer, rr4[i]) } //m.Extra = append(m.Extra, t) case dns.TypeAAAA: for i := 0; i < len(rr6); i++ { m.Answer = append(m.Answer, rr6[i]) } //m.Extra = append(m.Extra, t) case dns.TypeNS: m.Answer = append(m.Answer, ns1) m.Answer = append(m.Answer, ns2) case dns.TypeSOA: m.Answer = append(m.Answer, soa) } if r.IsTsig() != nil { if w.TsigStatus() == nil { m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix()) } else { println("Status", w.TsigStatus().Error()) } } if *printf { fmt.Printf("%v\n", m.String()) } w.WriteMsg(m) } func serve(net, name, secret string, soreuseport bool) { switch name { case "": server := &dns.Server{Addr: ":53", Net: net, TsigSecret: nil, ReusePort: soreuseport} if err := server.ListenAndServe(); err != nil { fmt.Printf("Failed to setup the "+net+" server: %s\n", err.Error()) } default: server := &dns.Server{Addr: ":8053", Net: net, TsigSecret: map[string]string{name: secret}, ReusePort: soreuseport} if err := server.ListenAndServe(); err != nil { fmt.Printf("Failed to setup the "+net+" server: %s\n", err.Error()) } } } func main() { var name, secret string flag.Usage = func() { flag.PrintDefaults() } flag.Parse() if *tsig != "" { a := strings.SplitN(*tsig, ":", 2) name, secret = dns.Fqdn(a[0]), a[1] // fqdn the name, which everybody forgets... } if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if *cpu != 0 { runtime.GOMAXPROCS(*cpu) } dns.HandleFunc(".", handleReflect) if *soreuseport > 0 { for i := 0; i < *soreuseport; i++ { go serve("tcp", name, secret, true) go serve("udp", name, secret, true) } } else { go serve("tcp", name, secret, false) go serve("udp", name, secret, false) } sig := make(chan os.Signal) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) s := <-sig fmt.Printf("Signal (%s) received, stopping\n", s) }