From 3c2b4a83ac16c06ed133e8d11f0ffa939b9143fa Mon Sep 17 00:00:00 2001 From: Joe Rozner Date: Sun, 21 Feb 2016 22:04:30 -0800 Subject: [PATCH] Clean up main package --- bruteforce.go | 70 +++++++++++++++++++++++ cmd/sonar/main.go | 137 ++-------------------------------------------- wildcard.go | 44 +++++++++++++++ zonetransfer.go | 50 +++++++++++++++++ 4 files changed, 168 insertions(+), 133 deletions(-) create mode 100644 bruteforce.go create mode 100644 wildcard.go create mode 100644 zonetransfer.go diff --git a/bruteforce.go b/bruteforce.go new file mode 100644 index 0000000..823d326 --- /dev/null +++ b/bruteforce.go @@ -0,0 +1,70 @@ +package sonar + +import ( + "fmt" + "net" + "sort" + "sync" +) + +func BruteForce(threads int, wordlist <-chan string, domain string) Results { + results := make(Results, 0) + + fmt.Println("[+] Detecting wildcard") + wildcard, responses, err := detectWildcard(domain) + if err != nil { + // TODO: Fail loudly + } + + if wildcard { + fmt.Println("[+] Wildcard detected for domain") + + wildcardResult := Result{ + Domain: "*." + domain, + Addrs: keys(responses), + } + + results = append(results, wildcardResult) + } + + fmt.Println("[+] Beginning brute force attempt") + + var wg sync.WaitGroup + for i := 0; i < threads; i++ { + wg.Add(1) + go func(wordlist <-chan string) { + nextWord: + for { + word, ok := <-wordlist + if !ok { + break + } + + guess := word + "." + domain + answers, err := net.LookupHost(word + "." + domain) + if err != nil { + continue + } + + if wildcard { + for _, answer := range answers { + if _, ok := responses[answer]; ok { + // it's a wildcard response + continue nextWord + } + } + } + + result := Result{Domain: guess, Addrs: answers} + results = append(results, result) + } + + wg.Done() + }(wordlist) + } + + wg.Wait() + sort.Sort(results) + + return results +} diff --git a/cmd/sonar/main.go b/cmd/sonar/main.go index d1e78ad..5010411 100644 --- a/cmd/sonar/main.go +++ b/cmd/sonar/main.go @@ -1,8 +1,6 @@ package main import ( - "crypto/rand" - "encoding/hex" "encoding/json" "encoding/xml" "flag" @@ -10,12 +8,8 @@ import ( "log" "net" "os" - "sort" - "strings" - "sync" "github.com/jrozner/sonar" - "github.com/miekg/dns" ) func main() { @@ -35,7 +29,7 @@ func main() { flag.IntVar(&threads, "threads", 4, "number of threads for brute forcing") flag.BoolVar(&zt, "zonetransfer", false, "perform zone transfer") flag.StringVar(&output, "output", "", "write output to specified file") - flag.StringVar(&format, "format", "", "output format (json, xml, csv, nmap)") + flag.StringVar(&format, "format", "", "output format (json, xml, nmap)") flag.Parse() if flag.NArg() != 1 { @@ -54,7 +48,7 @@ func main() { switch { case (zt == true): - results = zoneTransfer(domain) + results = sonar.ZoneTransfer(domain) case (brute == true): var wl sonar.Wordlist if wordlist == "" { @@ -66,7 +60,7 @@ func main() { } wl = sonar.NewFile(fp) } - results = bruteForce(threads, wl.GetChannel(), domain) + results = sonar.BruteForce(threads, wl.GetChannel(), domain) } if output == "" { @@ -94,7 +88,7 @@ func writeOutput(output, format string, results sonar.Results) error { case "nmap": serialized, err = sonar.ToNmap(results) default: - // TODO: return error for invalid format + log.Fatal("invalid output format") } if err != nil { @@ -109,135 +103,12 @@ func writeOutput(output, format string, results sonar.Results) error { return nil } -func zoneTransfer(domain string) sonar.Results { - results := sonar.NewResultSet() - fqdn := dns.Fqdn(domain) - - servers, err := net.LookupNS(domain) - if err != nil { - log.Fatal(err) - } - - for _, server := range servers { - msg := new(dns.Msg) - msg.SetAxfr(fqdn) - - transfer := new(dns.Transfer) - answerChan, err := transfer.In(msg, net.JoinHostPort(server.Host, "53")) - if err != nil { - log.Println(err) - continue - } - - for envelope := range answerChan { - if envelope.Error != nil { - log.Println(envelope.Error) - break - } - - for _, rr := range envelope.RR { - switch v := rr.(type) { - case *dns.A: - results.Add(strings.TrimRight(v.Header().Name, "."), v.A.String()) - case *dns.AAAA: - results.Add(strings.TrimRight(v.Header().Name, "."), v.AAAA.String()) - default: - } - } - } - } - - return results.Results() -} - -func bruteForce(threads int, wordlist <-chan string, domain string) sonar.Results { - fmt.Println("[+] Detecting wildcard") - wildcard, responses, err := detectWildcard(domain) - if err != nil { - // TODO: Fail loudly - } - - if wildcard { - fmt.Println("[+] Wildcard detected for domain") - } - - fmt.Println("[+] Beginning brute force attempt") - - results := make(sonar.Results, 0) - - var wg sync.WaitGroup - for i := 0; i < threads; i++ { - wg.Add(1) - go func(wordlist <-chan string) { - nextWord: - for { - word, ok := <-wordlist - if !ok { - break - } - - guess := word + "." + domain - answers, err := net.LookupHost(word + "." + domain) - if err != nil { - continue - } - - if wildcard { - for _, answer := range answers { - if _, ok := responses[answer]; ok { - // it's a wildcard response - continue nextWord - } - } - } - - result := sonar.Result{Domain: guess, Addrs: answers} - results = append(results, result) - } - - wg.Done() - }(wordlist) - } - - wg.Wait() - sort.Sort(results) - - return results -} - func printResults(results sonar.Results) { for _, result := range results { fmt.Println(result) } } -func detectWildcard(domain string) (bool, map[string]struct{}, error) { - bytes := make([]byte, 12) - _, err := rand.Read(bytes) - if err != nil { - return false, nil, err - } - - domain = fmt.Sprintf("%s.%s", hex.EncodeToString(bytes), domain) - - answers, err := net.LookupHost(domain) - if err != nil { - if asserted, ok := err.(*net.DNSError); ok && asserted.Err == "no such host" { - return false, nil, nil - } - - return false, nil, err - } - - responses := make(map[string]struct{}) - - for _, answer := range answers { - responses[answer] = struct{}{} - } - - return true, responses, nil -} - func printUsage() { fmt.Fprintf(os.Stderr, "Usage: %s [options] domain\n", os.Args[0]) flag.PrintDefaults() diff --git a/wildcard.go b/wildcard.go new file mode 100644 index 0000000..fcfca23 --- /dev/null +++ b/wildcard.go @@ -0,0 +1,44 @@ +package sonar + +import ( + "crypto/rand" + "encoding/hex" + "fmt" + "net" +) + +func detectWildcard(domain string) (bool, map[string]struct{}, error) { + bytes := make([]byte, 12) + _, err := rand.Read(bytes) + if err != nil { + return false, nil, err + } + + domain = fmt.Sprintf("%s.%s", hex.EncodeToString(bytes), domain) + + answers, err := net.LookupHost(domain) + if err != nil { + if asserted, ok := err.(*net.DNSError); ok && asserted.Err == "no such host" { + return false, nil, nil + } + + return false, nil, err + } + + responses := make(map[string]struct{}) + + for _, answer := range answers { + responses[answer] = struct{}{} + } + + return true, responses, nil +} + +func keys(set map[string]struct{}) []string { + keys := make([]string, 0, len(set)) + for key, _ := range set { + keys = append(keys, key) + } + + return keys +} diff --git a/zonetransfer.go b/zonetransfer.go new file mode 100644 index 0000000..750709c --- /dev/null +++ b/zonetransfer.go @@ -0,0 +1,50 @@ +package sonar + +import ( + "log" + "net" + "strings" + + "github.com/miekg/dns" +) + +func ZoneTransfer(domain string) Results { + results := NewResultSet() + fqdn := dns.Fqdn(domain) + + servers, err := net.LookupNS(domain) + if err != nil { + log.Fatal(err) + } + + for _, server := range servers { + msg := new(dns.Msg) + msg.SetAxfr(fqdn) + + transfer := new(dns.Transfer) + answerChan, err := transfer.In(msg, net.JoinHostPort(server.Host, "53")) + if err != nil { + log.Println(err) + continue + } + + for envelope := range answerChan { + if envelope.Error != nil { + log.Println(envelope.Error) + break + } + + for _, rr := range envelope.RR { + switch v := rr.(type) { + case *dns.A: + results.Add(strings.TrimRight(v.Header().Name, "."), v.A.String()) + case *dns.AAAA: + results.Add(strings.TrimRight(v.Header().Name, "."), v.AAAA.String()) + default: + } + } + } + } + + return results.Results() +}