Imported Upstream version 1.1
Sophie Brun
7 years ago
0 | Gobuster v1.0 (OJ Reeves @TheColonial) | |
0 | Gobuster v1.1 (OJ Reeves @TheColonial) | |
1 | 1 | ====================================== |
2 | 2 | |
3 | 3 | Alternative directory and file busting tool written in Go. DNS support recently added after inspiration and effort from [Peleus](https://twitter.com/0x42424242). |
26 | 26 | ### Common Command line options |
27 | 27 | |
28 | 28 | * `-m <mode>` - which mode to use, either `dir` or `dns` (default: `dir`) |
29 | * `-t <threads>` - number of threads to run (default: `10`). | |
29 | 30 | * `-u <url/domain>` - full URL (including scheme), or base domain name. |
30 | * `-t <threads>` - number of threads to run (default: `10`). | |
31 | * `-v` - verbose output (show all results). | |
31 | 32 | * `-w <wordlist>` - path to the wordlist used for brute forcing. |
32 | * `-v` - verbose output (show all results). | |
33 | 33 | |
34 | 34 | ### Command line options for `dns` mode |
35 | 35 | |
37 | 37 | |
38 | 38 | ### Command line options for `dir` mode |
39 | 39 | |
40 | * `-a <user agent string>` - specify a user agent string to send in the request header | |
40 | 41 | * `-c <http cookies>` - use this to specify any cookies that you might need (simulating auth). |
41 | 42 | * `-f` - append `/` for directory brute forces. |
42 | * `-r` - follow redirects. | |
43 | 43 | * `-l` - show the length of the response. |
44 | 44 | * `-n` - "no status" mode, disables the output of the result's status code. |
45 | * `-p <proxy url>` - specify a proxy to use for all requests (scheme much match the URL scheme) | |
45 | 46 | * `-q` - disables banner/underline output. |
46 | * `-e` - expand the results to include the full URL. | |
47 | * `-r` - follow redirects. | |
47 | 48 | * `-s <status codes>` - comma-separated set of the list of status codes to be deemed a "positive" (default: `200,204,301,302,307`). |
48 | 49 | * `-x <extensions>` - list of extensions to check for, if any. |
49 | * `-p <proxy url>` - specify a proxy to use for all requests (scheme much match the URL scheme) | |
50 | * `-P <password>` - HTTP Authorization password (Basic Auth only, prompted if missing). | |
51 | * `-U <username>` - HTTP Authorization username (Basic Auth only). | |
50 | 52 | |
51 | 53 | ### Building |
52 | 54 | |
57 | 59 | gobuster$ go build |
58 | 60 | ``` |
59 | 61 | This will create a `gobuster` binary for you. |
62 | ||
60 | 63 | #### Running as a script |
61 | 64 | ``` |
62 | 65 | gobuster$ go run main.go <parameters> |
74 | 77 | ``` |
75 | 78 | $ ./gobuster -u http://buffered.io/ -w words.txt |
76 | 79 | |
77 | ===================================================== | |
78 | Gobuster v1.0 (DIR support by OJ Reeves @TheColonial) | |
79 | (DNS support by Peleus @0x42424242) | |
80 | Gobuster v1.1 OJ Reeves (@TheColonial) | |
80 | 81 | ===================================================== |
81 | 82 | [+] Mode : dir |
82 | 83 | [+] Url/Domain : http://buffered.io/ |
93 | 94 | ``` |
94 | 95 | $ ./gobuster -u http://buffered.io/ -w words.txt -n |
95 | 96 | |
96 | ===================================================== | |
97 | Gobuster v1.0 (DIR support by OJ Reeves @TheColonial) | |
98 | (DNS support by Peleus @0x42424242) | |
97 | Gobuster v1.1 OJ Reeves (@TheColonial) | |
99 | 98 | ===================================================== |
100 | 99 | [+] Mode : dir |
101 | 100 | [+] Url/Domain : http://buffered.io/ |
113 | 112 | ``` |
114 | 113 | $ ./gobuster -u http://buffered.io/ -w words.txt -v |
115 | 114 | |
116 | ===================================================== | |
117 | Gobuster v1.0 (DIR support by OJ Reeves @TheColonial) | |
118 | (DNS support by Peleus @0x42424242) | |
115 | Gobuster v1.1 OJ Reeves (@TheColonial) | |
119 | 116 | ===================================================== |
120 | 117 | [+] Mode : dir |
121 | 118 | [+] Url/Domain : http://buffered.io/ |
132 | 129 | ``` |
133 | 130 | Example showing content length: |
134 | 131 | ``` |
135 | ===================================================== | |
136 | Gobuster v1.0 (DIR support by OJ Reeves @TheColonial) | |
137 | (DNS support by Peleus @0x42424242) | |
132 | $ ./gobuster -u http://buffered.io/ -w words.txt -l | |
133 | ||
134 | Gobuster v1.1 OJ Reeves (@TheColonial) | |
138 | 135 | ===================================================== |
139 | 136 | [+] Mode : dir |
140 | 137 | [+] Url/Domain : http://buffered.io/ |
141 | 138 | [+] Threads : 10 |
142 | 139 | [+] Wordlist : /tmp/words |
143 | 140 | [+] Status codes : 301,302,307,200,204 |
141 | [+] Show length : true | |
144 | 142 | ===================================================== |
145 | 143 | /contact (Status: 301) |
146 | 144 | /posts (Status: 301) |
165 | 163 | ``` |
166 | 164 | $ ./gobuster -m dns -w subdomains.txt -u google.com |
167 | 165 | |
168 | ===================================================== | |
169 | Gobuster v1.0 (DIR support by OJ Reeves @TheColonial) | |
170 | (DNS support by Peleus @0x42424242) | |
166 | Gobuster v1.1 OJ Reeves (@TheColonial) | |
171 | 167 | ===================================================== |
172 | 168 | [+] Mode : dns |
173 | 169 | [+] Url/Domain : google.com |
198 | 194 | ``` |
199 | 195 | $ ./gobuster -m dns -w subdomains.txt -u google.com -i |
200 | 196 | |
201 | ===================================================== | |
202 | Gobuster v1.0 (DIR support by OJ Reeves @TheColonial) | |
203 | (DNS support by Peleus @0x42424242) | |
197 | Gobuster v1.1 OJ Reeves (@TheColonial) | |
204 | 198 | ===================================================== |
205 | 199 | [+] Mode : dns |
206 | 200 | [+] Url/Domain : google.com |
228 | 222 | Found: mail.google.com [216.58.220.101, 2404:6800:4006:801::2005] |
229 | 223 | ===================================================== |
230 | 224 | ``` |
225 | Base domain validation warning when the base domain fails to resolve. This is a warning rather than a failure in case the user fat-fingers while typing the domain. | |
226 | ``` | |
227 | $ ./gobuster -m dns -w subdomains.txt -u yp.to -i | |
228 | ||
229 | Gobuster v1.1 OJ Reeves (@TheColonial) | |
230 | ===================================================== | |
231 | [+] Mode : dns | |
232 | [+] Url/Domain : yp.to | |
233 | [+] Threads : 10 | |
234 | [+] Wordlist : /tmp/test.txt | |
235 | ===================================================== | |
236 | [!] Unable to validate base domain: yp.to | |
237 | Found: cr.yp.to [131.155.70.11, 131.155.70.13] | |
238 | ===================================================== | |
239 | ``` | |
231 | 240 | |
232 | 241 | ### License |
233 | 242 | |
235 | 244 | |
236 | 245 | ### Thanks |
237 | 246 | |
238 | See the THANKS file. | |
247 | See the THANKS file for people who helped out. |
0 | g0tmi1k | |
1 | peleus | |
2 | UID1K | |
3 | averagesecurityguy | |
0 | @0x42424242 - initial DNS support | |
1 | @averagesecurityguy - quiet mode support | |
2 | @g0tmi1k - content length, wordlist and command line parsing fixes | |
3 | @justinsteven - HTTP basic auth support | |
4 | @kevinnz - custom user agent support | |
5 | @viaMorgoth - base domain validation for DNS mode | |
6 | @UID1K - DNS wildcard check support |
9 | 9 | // to native code is also appealing. |
10 | 10 | // |
11 | 11 | // Run: gobuster -h |
12 | // | |
13 | // Please see THANKS file for contributors. | |
14 | // Please see LICENSE file for license details. | |
15 | // | |
12 | 16 | //---------------------------------------------------- |
13 | 17 | |
14 | 18 | import ( |
16 | 20 | "crypto/tls" |
17 | 21 | "flag" |
18 | 22 | "fmt" |
23 | "golang.org/x/crypto/ssh/terminal" | |
19 | 24 | "io/ioutil" |
20 | 25 | "net" |
21 | 26 | "net/http" |
24 | 29 | "strconv" |
25 | 30 | "strings" |
26 | 31 | "sync" |
32 | "syscall" | |
27 | 33 | "unicode/utf8" |
28 | 34 | ) |
29 | 35 | |
48 | 54 | // Contains State that are read in from the command |
49 | 55 | // line when the program is invoked. |
50 | 56 | type State struct { |
51 | Threads int | |
52 | Wordlist string | |
53 | Url string | |
57 | Client *http.Client | |
54 | 58 | Cookies string |
59 | Expanded bool | |
55 | 60 | Extensions []string |
56 | StatusCodes IntSet | |
57 | Verbose bool | |
58 | UseSlash bool | |
59 | 61 | FollowRedirect bool |
60 | 62 | IncludeLength bool |
61 | ShowIPs bool | |
62 | Quiet bool | |
63 | Mode string | |
63 | 64 | NoStatus bool |
64 | Expanded bool | |
65 | Mode string | |
66 | ProxyUrl *url.URL | |
67 | Setup SetupFunc | |
65 | Password string | |
68 | 66 | Printer PrintResultFunc |
69 | 67 | Processor ProcessorFunc |
70 | Client *http.Client | |
68 | ProxyUrl *url.URL | |
69 | Quiet bool | |
70 | Setup SetupFunc | |
71 | ShowIPs bool | |
72 | StatusCodes IntSet | |
73 | Threads int | |
74 | Url string | |
75 | UseSlash bool | |
76 | UserAgent string | |
77 | Username string | |
78 | Verbose bool | |
79 | Wordlist string | |
71 | 80 | } |
72 | 81 | |
73 | 82 | type RedirectHandler struct { |
111 | 120 | |
112 | 121 | if cookie != "" { |
113 | 122 | req.Header.Set("Cookie", cookie) |
123 | } | |
124 | ||
125 | if s.UserAgent != "" { | |
126 | req.Header.Set("User-Agent", s.UserAgent) | |
127 | } | |
128 | ||
129 | if s.Username != "" { | |
130 | req.SetBasicAuth(s.Username, s.Password) | |
114 | 131 | } |
115 | 132 | |
116 | 133 | resp, err := s.Client.Do(req) |
166 | 183 | flag.StringVar(&codes, "s", "200,204,301,302,307", "Positive status codes (dir mode only)") |
167 | 184 | flag.StringVar(&s.Url, "u", "", "The target URL or Domain") |
168 | 185 | flag.StringVar(&s.Cookies, "c", "", "Cookies to use for the requests (dir mode only)") |
186 | flag.StringVar(&s.Username, "U", "", "Username for Basic Auth (dir mode only)") | |
187 | flag.StringVar(&s.Password, "P", "", "Password for Basic Auth (dir mode only)") | |
169 | 188 | flag.StringVar(&extensions, "x", "", "File extension(s) to search for (dir mode only)") |
189 | flag.StringVar(&s.UserAgent, "a", "", "Set the User-Agent string (dir mode only)") | |
170 | 190 | flag.StringVar(&proxy, "p", "", "Proxy to use for requests [http(s)://host:port] (dir mode only)") |
171 | 191 | flag.BoolVar(&s.Verbose, "v", false, "Verbose output (errors)") |
172 | 192 | flag.BoolVar(&s.ShowIPs, "i", false, "Show IP addresses (dns mode only)") |
173 | 193 | flag.BoolVar(&s.FollowRedirect, "r", false, "Follow redirects") |
174 | flag.BoolVar(&s.Quiet, "q", false, "Don't print the banner") | |
194 | flag.BoolVar(&s.Quiet, "q", false, "Don't print the banner and other noise") | |
175 | 195 | flag.BoolVar(&s.Expanded, "e", false, "Expanded mode, print full URLs") |
176 | 196 | flag.BoolVar(&s.NoStatus, "n", false, "Don't print status codes") |
177 | 197 | flag.BoolVar(&s.IncludeLength, "l", false, "Include the length of the body in the output (dir mode only)") |
178 | 198 | flag.BoolVar(&s.UseSlash, "f", false, "Append a forward-slash to each directory request (dir mode only)") |
179 | 199 | |
180 | 200 | flag.Parse() |
201 | ||
202 | Banner(&s) | |
181 | 203 | |
182 | 204 | switch strings.ToLower(s.Mode) { |
183 | 205 | case "dir": |
241 | 263 | } |
242 | 264 | } |
243 | 265 | |
266 | // prompt for password if needed | |
267 | if valid && s.Username != "" && s.Password == "" { | |
268 | fmt.Printf("[?] Auth Password: ") | |
269 | passBytes, err := terminal.ReadPassword(int(syscall.Stdin)) | |
270 | ||
271 | // print a newline to simulate the newline that was entered | |
272 | // this means that formatting/printing after doesn't look bad. | |
273 | fmt.Println("") | |
274 | ||
275 | if err == nil { | |
276 | s.Password = string(passBytes) | |
277 | } else { | |
278 | panic("Auth username given but reading of password failed") | |
279 | } | |
280 | } | |
281 | ||
244 | 282 | if valid { |
245 | 283 | var proxyUrlFunc func(*http.Request) (*url.URL, error) |
246 | 284 | proxyUrlFunc = http.ProxyFromEnvironment |
288 | 326 | panic("Failed to open wordlist") |
289 | 327 | } |
290 | 328 | |
291 | Banner(s) | |
329 | ShowConfig(s) | |
292 | 330 | |
293 | 331 | if s.Setup(s) == false { |
294 | 332 | Ruler(s) |
342 | 380 | // Lazy reading of the wordlist line by line |
343 | 381 | scanner := bufio.NewScanner(wordlist) |
344 | 382 | for scanner.Scan() { |
345 | word := scanner.Text() | |
346 | ||
347 | // Skip "comment" lines | |
348 | if strings.HasPrefix(word, "#") == false { | |
383 | word := strings.TrimSpace(scanner.Text()) | |
384 | ||
385 | // Skip "comment" (starts with #), as well as empty lines | |
386 | if !strings.HasPrefix(word, "#") && len(word) > 0 { | |
349 | 387 | wordChan <- word |
350 | 388 | } |
351 | 389 | } |
361 | 399 | // Resolve a subdomain that probably shouldn't exist |
362 | 400 | _, err := net.LookupHost("bba1b18d-50f8-4f1d-8295-c861445ed7f5." + s.Url) |
363 | 401 | if err == nil { |
364 | fmt.Println("Wildcard DNS found.") | |
402 | fmt.Println("[-] Wildcard DNS found.") | |
365 | 403 | return false |
366 | 404 | } |
405 | ||
406 | if !s.Quiet { | |
407 | // Provide a warning if the base domain doesn't resolve (in case of typo) | |
408 | _, err = net.LookupHost(s.Url) | |
409 | if err != nil { | |
410 | // Not an error, just a warning. Eg. `yp.to` doesn't resolve, but `cr.py.to` does! | |
411 | fmt.Println("[!] Unable to validate base domain:", s.Url) | |
412 | } | |
413 | } | |
414 | ||
367 | 415 | return true |
368 | 416 | } |
369 | 417 | |
500 | 548 | } |
501 | 549 | |
502 | 550 | fmt.Println("") |
551 | fmt.Println("Gobuster v1.1 OJ Reeves (@TheColonial)") | |
503 | 552 | Ruler(state) |
504 | fmt.Println("Gobuster v1.0 (DIR support by OJ Reeves @TheColonial)") | |
505 | fmt.Println(" (DNS support by Peleus @0x42424242)") | |
506 | Ruler(state) | |
553 | } | |
554 | ||
555 | func ShowConfig(state *State) { | |
556 | if state.Quiet { | |
557 | return | |
558 | } | |
507 | 559 | |
508 | 560 | if state != nil { |
509 | 561 | fmt.Printf("[+] Mode : %s\n", state.Mode) |
522 | 574 | fmt.Printf("[+] Cookies : %s\n", state.Cookies) |
523 | 575 | } |
524 | 576 | |
577 | if state.UserAgent != "" { | |
578 | fmt.Printf("[+] User Agent : %s\n", state.UserAgent) | |
579 | } | |
580 | ||
581 | if state.IncludeLength { | |
582 | fmt.Printf("[+] Show length : true\n") | |
583 | } | |
584 | ||
585 | if state.Username != "" { | |
586 | fmt.Printf("[+] Auth User : %s\n", state.Username) | |
587 | } | |
588 | ||
525 | 589 | if len(state.Extensions) > 0 { |
526 | 590 | fmt.Printf("[+] Extensions : %s\n", strings.Join(state.Extensions, ",")) |
527 | 591 | } |