yellow~ opinionated web scanning pipeline for pentesters in a hurry |
| git clone https://github.com/djnnvx/yellow.git |
| log | files | refs | archive | README | LICENSE |
gau.go (2798B)
1 package osint 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net/url" 8 "strings" 9 "time" 10 11 "evil.djnn.sh/djnn/yellow/core" 12 mapset "github.com/deckarep/golang-set/v2" 13 "github.com/lc/gau/v2/pkg/providers" 14 "github.com/lc/gau/v2/runner" 15 "github.com/valyala/fasthttp" 16 "github.com/valyala/fasthttp/fasthttpproxy" 17 ) 18 19 type Gau struct{} 20 21 func (*Gau) Name() string { return "gau" } 22 23 func (*Gau) Run(ctx *core.Context) error { 24 fmt.Println("[+] Running gau on", ctx.Domain) 25 if ctx.DryRun { 26 return nil 27 } 28 29 domain := gauDomain(ctx.Domain) 30 31 client := &fasthttp.Client{ 32 ReadTimeout: 30 * time.Second, 33 WriteTimeout: 30 * time.Second, 34 TLSConfig: &tls.Config{InsecureSkipVerify: true}, 35 } 36 if ctx.Proxy != "" { 37 host := strings.TrimPrefix(strings.TrimPrefix(ctx.Proxy, "http://"), "https://") 38 client.Dial = fasthttpproxy.FasthttpHTTPDialer(host) 39 } 40 41 config := &providers.Config{ 42 Threads: 3, 43 Timeout: 45, 44 MaxRetries: 2, 45 IncludeSubdomains: true, 46 Client: client, 47 Providers: []string{"wayback", "commoncrawl", "otx", "urlscan"}, 48 Blacklist: mapset.NewSet[string](), 49 // URLScan.Host left empty so gau uses its built-in default base URL 50 } 51 52 // init providers one at a time so a single unreachable one (commoncrawl 53 // fetches its index at instantiation) doesn't take down the rest. 54 gau := &runner.Runner{} 55 for _, p := range config.Providers { 56 if err := gau.Init(config, []string{p}, providers.Filters{}); err != nil { 57 fmt.Printf("[!] gau: skipping provider %s: %v\n", p, err) 58 } 59 } 60 if len(gau.Providers) == 0 { 61 fmt.Println("[!] gau: no providers available, skipping") 62 return nil 63 } 64 65 results := make(chan string) 66 seen := map[string]struct{}{} 67 var urls []string 68 done := make(chan struct{}) 69 go func() { 70 for u := range results { 71 if _, ok := seen[u]; ok { 72 continue 73 } 74 seen[u] = struct{}{} 75 urls = append(urls, u) 76 } 77 close(done) 78 }() 79 80 rctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) 81 defer cancel() 82 83 // buffered + filled before Start so a cancelled rctx can't deadlock the sends 84 workChan := make(chan runner.Work, len(gau.Providers)) 85 for _, p := range gau.Providers { 86 workChan <- runner.NewWork(domain, p) 87 } 88 close(workChan) 89 gau.Start(rctx, workChan, results) 90 gau.Wait() 91 close(results) 92 <-done 93 94 outfile := fmt.Sprintf("%s/urls.txt", ctx.ScanPath) 95 if err := core.WriteLines(outfile, urls); err != nil { 96 fmt.Printf("[!] gau: could not write %s: %v\n", outfile, err) 97 return nil 98 } 99 100 fmt.Printf("[OSINT %s] gau collected %d historical URL(s) in %s\n", domain, len(urls), outfile) 101 return nil 102 } 103 104 func gauDomain(target string) string { 105 if u, err := url.Parse(target); err == nil && u.Hostname() != "" { 106 return u.Hostname() 107 } 108 return strings.TrimSpace(target) 109 }