New upstream snapshot.
Kali Janitor
1 year, 7 months ago
5 | 5 | runs-on: ubuntu-latest |
6 | 6 | strategy: |
7 | 7 | matrix: |
8 | go: ["1.13.10", "1.14.2"] | |
8 | go: ["1.17", "1.18", "1.19"] | |
9 | 9 | steps: |
10 | 10 | - name: Set up Go ${{ matrix.go }} |
11 | uses: actions/setup-go@v1 | |
11 | uses: actions/setup-go@v2 | |
12 | 12 | with: |
13 | 13 | go-version: ${{ matrix.go }} |
14 | id: go | |
15 | 14 | |
16 | - name: Check out code into the Go module directory | |
15 | - name: Check out code | |
17 | 16 | uses: actions/checkout@v2 |
17 | ||
18 | - name: build cache | |
19 | uses: actions/cache@v2 | |
20 | with: | |
21 | path: ~/go/pkg/mod | |
22 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | |
23 | restore-keys: | | |
24 | ${{ runner.os }}-go- | |
18 | 25 | |
19 | 26 | - name: Get dependencies |
20 | 27 | run: | |
21 | 28 | go get -v -t -d ./... |
22 | if [ -f Gopkg.toml ]; then | |
23 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh | |
24 | dep ensure | |
25 | fi | |
26 | 29 | |
27 | 30 | - name: Build |
28 | 31 | run: go build -v . |
29 | 32 | |
30 | 33 | - name: Test |
31 | 34 | run: make test |
32 | ||
33 | - name: Lint | |
34 | run: make lint |
0 | name: golangci-lint | |
1 | on: [push, pull_request] | |
2 | jobs: | |
3 | golangci: | |
4 | name: lint | |
5 | runs-on: ubuntu-latest | |
6 | steps: | |
7 | - uses: actions/checkout@v2 | |
8 | - name: golangci-lint | |
9 | uses: golangci/golangci-lint-action@v2 | |
10 | with: | |
11 | version: latest |
0 | linters: | |
1 | enable-all: true | |
2 | disable: | |
3 | - wsl | |
4 | - gocyclo | |
5 | - gocognit | |
6 | - funlen | |
7 | - lll | |
8 | - dogsled | |
9 | - gomnd | |
10 | - nestif | |
11 | - testpackage | |
12 | - godot | |
13 | - goerr113 | |
14 | - gofumpt | |
15 | ||
16 | issues: | |
17 | exclude-rules: | |
18 | - text: "TLS InsecureSkipVerify may be true" | |
19 | linters: | |
20 | - gosec | |
21 | ||
22 | - text: ifElseChain | |
23 | linters: | |
24 | - gocritic | |
25 | ||
26 | - path: cli\\cmd\\.+\.go | |
27 | linters: | |
28 | - gochecknoinits | |
29 | - gochecknoglobals | |
30 | ||
31 | - path: cli/cmd/.+\.go | |
32 | linters: | |
33 | - gochecknoinits | |
34 | - gochecknoglobals | |
35 | ||
36 | - path: helper/useragents.go | |
37 | linters: | |
38 | - gochecknoglobals | |
39 | ||
40 | - path: _test\.go | |
41 | linters: | |
42 | - scopelint |
0 | 0 | FROM golang:latest AS build-env |
1 | 1 | WORKDIR /src |
2 | ENV GO111MODULE=on | |
2 | ENV CGO_ENABLED=0 | |
3 | 3 | COPY go.mod /src/ |
4 | 4 | RUN go mod download |
5 | 5 | COPY . . |
6 | RUN CGO_ENABLED=0 GOOS=linux go build -a -o gobuster -ldflags="-s -w" -gcflags="all=-trimpath=/src" -asmflags="all=-trimpath=/src" | |
6 | RUN go build -a -o gobuster -ldflags="-s -w" -gcflags="all=-trimpath=/src" -asmflags="all=-trimpath=/src" | |
7 | 7 | |
8 | 8 | FROM alpine:latest |
9 | 9 |
1 | 1 | ARCHS=amd64 386 |
2 | 2 | LDFLAGS="-s -w" |
3 | 3 | |
4 | .PHONY: current | |
4 | 5 | current: |
5 | 6 | @go build -o ./gobuster; \ |
6 | 7 | echo "Done." |
7 | 8 | |
9 | .PHONY: fmt | |
8 | 10 | fmt: |
9 | 11 | @go fmt ./...; \ |
10 | 12 | echo "Done." |
11 | 13 | |
14 | .PHONY: update | |
12 | 15 | update: |
13 | 16 | @go get -u; \ |
14 | 17 | go mod tidy -v; \ |
15 | 18 | echo "Done." |
16 | 19 | |
20 | .PHONY: windows | |
17 | 21 | windows: |
18 | 22 | @for GOARCH in ${ARCHS}; do \ |
19 | 23 | echo "Building for windows $${GOARCH} ..." ; \ |
22 | 26 | done; \ |
23 | 27 | echo "Done." |
24 | 28 | |
29 | .PHONY: linux | |
25 | 30 | linux: |
26 | 31 | @for GOARCH in ${ARCHS}; do \ |
27 | 32 | echo "Building for linux $${GOARCH} ..." ; \ |
30 | 35 | done; \ |
31 | 36 | echo "Done." |
32 | 37 | |
38 | .PHONY: darwin | |
33 | 39 | darwin: |
34 | 40 | @for GOARCH in ${ARCHS}; do \ |
35 | 41 | echo "Building for darwin $${GOARCH} ..." ; \ |
38 | 44 | done; \ |
39 | 45 | echo "Done." |
40 | 46 | |
47 | .PHONY: all | |
41 | 48 | all: clean fmt update test lint darwin linux windows |
42 | 49 | |
50 | .PHONY: test | |
43 | 51 | test: |
44 | 52 | @go test -v -race ./... ; \ |
45 | 53 | echo "Done." |
46 | 54 | |
55 | .PHONY: lint | |
47 | 56 | lint: |
48 | @if [ ! -f "$$(go env GOPATH)/bin/golangci-lint" ]; then \ | |
49 | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin v1.29.0; \ | |
50 | fi | |
51 | 57 | "$$(go env GOPATH)/bin/golangci-lint" run ./... |
52 | 58 | go mod tidy |
53 | 59 | |
60 | .PHONY: lint-update | |
61 | lint-update: | |
62 | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin | |
63 | $$(go env GOPATH)/bin/golangci-lint --version | |
64 | ||
65 | .PHONY: lint-docker | |
66 | lint-docker: | |
67 | docker pull golangci/golangci-lint:latest | |
68 | docker run --rm -v $$(pwd):/app -w /app golangci/golangci-lint:latest golangci-lint run | |
69 | ||
70 | .PHONY: clean | |
54 | 71 | clean: |
55 | 72 | @rm -rf ${TARGET}/* ; \ |
56 | 73 | go clean ./... ; \ |
1 | 1 | |
2 | 2 | Gobuster is a tool used to brute-force: |
3 | 3 | |
4 | * URIs (directories and files) in web sites. | |
5 | * DNS subdomains (with wildcard support). | |
6 | * Virtual Host names on target web servers. | |
7 | * Open Amazon S3 buckets | |
4 | - URIs (directories and files) in web sites. | |
5 | - DNS subdomains (with wildcard support). | |
6 | - Virtual Host names on target web servers. | |
7 | - Open Amazon S3 buckets | |
8 | 8 | |
9 | 9 | ## Tags, Statuses, etc |
10 | 10 | |
28 | 28 | |
29 | 29 | Yes, you're probably correct. Feel free to: |
30 | 30 | |
31 | * Not use it. | |
32 | * Show me how to do it better. | |
31 | - Not use it. | |
32 | - Show me how to do it better. | |
33 | 33 | |
34 | 34 | ## Love this tool? Back it! |
35 | 35 | |
39 | 39 | |
40 | 40 | All funds that are donated to this project will be donated to charity. A full log of charity donations will be available in this repository as they are processed. |
41 | 41 | |
42 | ## Changes in 3.1-dev | |
43 | ||
44 | - Use go 1.16 | |
45 | - use contexts in the correct way | |
46 | - get rid of the wildcard flag (except in DNS mode) | |
47 | ||
42 | 48 | ## Changes in 3.1 |
43 | 49 | |
44 | * enumerate public AWS S3 buckets | |
45 | * fuzzing mode | |
46 | * specify HTTP method | |
47 | * added support for patterns. You can now specify a file containing patterns that are applied to every word, one by line. Every occurrence of the term `{GOBUSTER}` in it will be replaced with the current wordlist item. Please use with caution as this can cause increase the number of requests issued a lot. | |
48 | * The shorthand `p` flag which was assigned to proxy is now used by the pattern flag | |
50 | - enumerate public AWS S3 buckets | |
51 | - fuzzing mode | |
52 | - specify HTTP method | |
53 | - added support for patterns. You can now specify a file containing patterns that are applied to every word, one by line. Every occurrence of the term `{GOBUSTER}` in it will be replaced with the current wordlist item. Please use with caution as this can cause increase the number of requests issued a lot. | |
54 | - The shorthand `p` flag which was assigned to proxy is now used by the pattern flag | |
49 | 55 | |
50 | 56 | ## Changes in 3.0 |
51 | 57 | |
52 | * New CLI options so modes are strictly separated (`-m` is now gone!) | |
53 | * Performance Optimizations and better connection handling | |
54 | * Ability to enumerate vhost names | |
55 | * Option to supply custom HTTP headers | |
58 | - New CLI options so modes are strictly separated (`-m` is now gone!) | |
59 | - Performance Optimizations and better connection handling | |
60 | - Ability to enumerate vhost names | |
61 | - Option to supply custom HTTP headers | |
56 | 62 | |
57 | 63 | ## Available Modes |
58 | 64 | |
59 | * dir - the classic directory brute-forcing mode | |
60 | * dns - DNS subdomain brute-forcing mode | |
61 | * s3 - Enumerate open S3 buckets and look for existence and bucket listings | |
62 | * vhost - virtual host brute-forcing mode (not the same as DNS!) | |
65 | - dir - the classic directory brute-forcing mode | |
66 | - dns - DNS subdomain brute-forcing mode | |
67 | - s3 - Enumerate open S3 buckets and look for existence and bucket listings | |
68 | - vhost - virtual host brute-forcing mode (not the same as DNS!) | |
63 | 69 | |
64 | 70 | ## Built-in Help |
65 | 71 | |
66 | 72 | Help is built-in! |
67 | 73 | |
68 | * `gobuster help` - outputs the top-level help. | |
69 | * `gobuster help <mode>` - outputs the help specific to that mode. | |
74 | - `gobuster help` - outputs the top-level help. | |
75 | - `gobuster help <mode>` - outputs the help specific to that mode. | |
70 | 76 | |
71 | 77 | ## `dns` Mode Help |
72 | 78 | |
168 | 174 | |
169 | 175 | If you're stupid enough to trust binaries that I've put together, you can download them from the [releases](https://github.com/OJ/gobuster/releases) page. |
170 | 176 | |
171 | ### Using `go get` | |
172 | ||
173 | If you have a [Go](https://golang.org/) environment ready to go, it's as easy as: | |
174 | ||
175 | ```bash | |
176 | go get github.com/OJ/gobuster | |
177 | ``` | |
177 | ### Using `go install` | |
178 | ||
179 | If you have a [Go](https://golang.org/) environment ready to go (at least go 1.17), it's as easy as: | |
180 | ||
181 | ```bash | |
182 | go install github.com/OJ/gobuster/v3@latest | |
183 | ``` | |
184 | ||
185 | PS: You need at least go 1.17.0 to compile gobuster. | |
178 | 186 | |
179 | 187 | ## Building From Source |
180 | 188 | |
181 | Since this tool is written in [Go](https://golang.org/) you need to install the Go language/compiler/etc. Full details of installation and set up can be found [on the Go language website](https://golang.org/doc/install). Once installed you have two options. | |
189 | Since this tool is written in [Go](https://golang.org/) you need to install the Go language/compiler/etc. Full details of installation and set up can be found [on the Go language website](https://golang.org/doc/install). Once installed you have two options. You need at least go 1.17.0 to compile gobuster. | |
182 | 190 | |
183 | 191 | ### Compiling |
184 | 192 | |
185 | `gobuster` now has external dependencies, and so they need to be pulled in first: | |
193 | `gobuster` has external dependencies, and so they need to be pulled in first: | |
186 | 194 | |
187 | 195 | ```bash |
188 | 196 | go get && go build |
196 | 204 | |
197 | 205 | If you have all the dependencies already, you can make use of the build scripts: |
198 | 206 | |
199 | * `make` - builds for the current Go configuration (ie. runs `go build`). | |
200 | * `make windows` - builds 32 and 64 bit binaries for windows, and writes them to the `build` folder. | |
201 | * `make linux` - builds 32 and 64 bit binaries for linux, and writes them to the `build` folder. | |
202 | * `make darwin` - builds 32 and 64 bit binaries for darwin, and writes them to the `build` folder. | |
203 | * `make all` - builds for all platforms and architectures, and writes the resulting binaries to the `build` folder. | |
204 | * `make clean` - clears out the `build` folder. | |
205 | * `make test` - runs the tests. | |
207 | - `make` - builds for the current Go configuration (ie. runs `go build`). | |
208 | - `make windows` - builds 32 and 64 bit binaries for windows, and writes them to the `build` folder. | |
209 | - `make linux` - builds 32 and 64 bit binaries for linux, and writes them to the `build` folder. | |
210 | - `make darwin` - builds 32 and 64 bit binaries for darwin, and writes them to the `build` folder. | |
211 | - `make all` - builds for all platforms and architectures, and writes the resulting binaries to the `build` folder. | |
212 | - `make clean` - clears out the `build` folder. | |
213 | - `make test` - runs the tests. | |
206 | 214 | |
207 | 215 | ## Wordlists via STDIN |
208 | 216 | |
576 | 584 | |
577 | 585 | #### Use case in combination with patterns |
578 | 586 | |
579 | * Create a custom wordlist for the target containing company names and so on | |
580 | * Create a pattern file to use for common bucket names. | |
587 | - Create a custom wordlist for the target containing company names and so on | |
588 | - Create a pattern file to use for common bucket names. | |
581 | 589 | |
582 | 590 | ```bash |
583 | 591 | curl -s --output - https://raw.githubusercontent.com/eth0izzle/bucket-stream/master/permutations/extended.txt | sed -s 's/%s/{GOBUSTER}/' > patterns.txt |
584 | 592 | ``` |
585 | 593 | |
586 | * Run gobuster with the custom input. Be sure to turn verbose mode on to see the bucket details | |
594 | - Run gobuster with the custom input. Be sure to turn verbose mode on to see the bucket details | |
587 | 595 | |
588 | 596 | ```bash |
589 | 597 | gobuster s3 --wordlist my.custom.wordlist -p patterns.txt -v |
0 | 0 | package cmd |
1 | 1 | |
2 | 2 | import ( |
3 | "errors" | |
3 | 4 | "fmt" |
4 | 5 | "log" |
5 | 6 | |
10 | 11 | "github.com/spf13/cobra" |
11 | 12 | ) |
12 | 13 | |
14 | // nolint:gochecknoglobals | |
13 | 15 | var cmdDir *cobra.Command |
14 | 16 | |
15 | 17 | func runDir(cmd *cobra.Command, args []string) error { |
18 | 20 | return fmt.Errorf("error on parsing arguments: %w", err) |
19 | 21 | } |
20 | 22 | |
21 | plugin, err := gobusterdir.NewGobusterDir(mainContext, globalopts, pluginopts) | |
23 | plugin, err := gobusterdir.NewGobusterDir(globalopts, pluginopts) | |
22 | 24 | if err != nil { |
23 | 25 | return fmt.Errorf("error on creating gobusterdir: %w", err) |
24 | 26 | } |
25 | 27 | |
26 | 28 | if err := cli.Gobuster(mainContext, globalopts, plugin); err != nil { |
27 | if goberr, ok := err.(*gobusterdir.ErrWildcard); ok { | |
28 | return fmt.Errorf("%s. To continue please exclude the status code, the length or use the --wildcard switch", goberr.Error()) | |
29 | var wErr *gobusterdir.ErrWildcard | |
30 | if errors.As(err, &wErr) { | |
31 | return fmt.Errorf("%w. To continue please exclude the status code or the length", wErr) | |
29 | 32 | } |
30 | 33 | return fmt.Errorf("error on running gobuster: %w", err) |
31 | 34 | } |
60 | 63 | if err != nil { |
61 | 64 | return nil, nil, fmt.Errorf("invalid value for extensions: %w", err) |
62 | 65 | } |
66 | ret, err := helper.ParseExtensions(plugin.Extensions) | |
67 | if err != nil { | |
68 | return nil, nil, fmt.Errorf("invalid value for extensions: %w", err) | |
69 | } | |
70 | plugin.ExtensionsParsed = ret | |
63 | 71 | |
64 | if plugin.Extensions != "" { | |
65 | ret, err := helper.ParseExtensions(plugin.Extensions) | |
66 | if err != nil { | |
67 | return nil, nil, fmt.Errorf("invalid value for extensions: %w", err) | |
68 | } | |
69 | plugin.ExtensionsParsed = ret | |
72 | // parse normal status codes | |
73 | plugin.StatusCodes, err = cmdDir.Flags().GetString("status-codes") | |
74 | if err != nil { | |
75 | return nil, nil, fmt.Errorf("invalid value for status-codes: %w", err) | |
70 | 76 | } |
77 | ret2, err := helper.ParseCommaSeparatedInt(plugin.StatusCodes) | |
78 | if err != nil { | |
79 | return nil, nil, fmt.Errorf("invalid value for status-codes: %w", err) | |
80 | } | |
81 | plugin.StatusCodesParsed = ret2 | |
71 | 82 | |
83 | // blacklist will override the normal status codes | |
72 | 84 | plugin.StatusCodesBlacklist, err = cmdDir.Flags().GetString("status-codes-blacklist") |
73 | 85 | if err != nil { |
74 | 86 | return nil, nil, fmt.Errorf("invalid value for status-codes-blacklist: %w", err) |
75 | 87 | } |
88 | ret3, err := helper.ParseCommaSeparatedInt(plugin.StatusCodesBlacklist) | |
89 | if err != nil { | |
90 | return nil, nil, fmt.Errorf("invalid value for status-codes-blacklist: %w", err) | |
91 | } | |
92 | plugin.StatusCodesBlacklistParsed = ret3 | |
76 | 93 | |
77 | // blacklist will override the normal status codes | |
78 | if plugin.StatusCodesBlacklist != "" { | |
79 | ret, err := helper.ParseCommaSeparatedInt(plugin.StatusCodesBlacklist) | |
80 | if err != nil { | |
81 | return nil, nil, fmt.Errorf("invalid value for status-codes-blacklist: %w", err) | |
82 | } | |
83 | plugin.StatusCodesBlacklistParsed = ret | |
84 | } else { | |
85 | // parse normal status codes | |
86 | plugin.StatusCodes, err = cmdDir.Flags().GetString("status-codes") | |
87 | if err != nil { | |
88 | return nil, nil, fmt.Errorf("invalid value for status-codes: %w", err) | |
89 | } | |
90 | ret, err := helper.ParseCommaSeparatedInt(plugin.StatusCodes) | |
91 | if err != nil { | |
92 | return nil, nil, fmt.Errorf("invalid value for status-codes: %w", err) | |
93 | } | |
94 | plugin.StatusCodesParsed = ret | |
94 | if plugin.StatusCodes != "" && plugin.StatusCodesBlacklist != "" { | |
95 | return nil, nil, fmt.Errorf("status-codes and status-codes-blacklist are both set, please set only one") | |
96 | } | |
97 | ||
98 | if plugin.StatusCodes == "" && plugin.StatusCodesBlacklist == "" { | |
99 | return nil, nil, fmt.Errorf("status-codes and status-codes-blacklist are both not set, please set one") | |
95 | 100 | } |
96 | 101 | |
97 | 102 | plugin.UseSlash, err = cmdDir.Flags().GetBool("add-slash") |
114 | 119 | return nil, nil, fmt.Errorf("invalid value for hide-length: %w", err) |
115 | 120 | } |
116 | 121 | |
117 | plugin.WildcardForced, err = cmdDir.Flags().GetBool("wildcard") | |
118 | if err != nil { | |
119 | return nil, nil, fmt.Errorf("invalid value for wildcard: %w", err) | |
120 | } | |
121 | ||
122 | 122 | plugin.DiscoverBackup, err = cmdDir.Flags().GetBool("discover-backup") |
123 | 123 | if err != nil { |
124 | 124 | return nil, nil, fmt.Errorf("invalid value for discover-backup: %w", err) |
132 | 132 | return globalopts, plugin, nil |
133 | 133 | } |
134 | 134 | |
135 | // nolint:gochecknoinits | |
135 | 136 | func init() { |
136 | 137 | cmdDir = &cobra.Command{ |
137 | 138 | Use: "dir", |
149 | 150 | cmdDir.Flags().BoolP("no-status", "n", false, "Don't print status codes") |
150 | 151 | cmdDir.Flags().Bool("hide-length", false, "Hide the length of the body in the output") |
151 | 152 | cmdDir.Flags().BoolP("add-slash", "f", false, "Append / to each request") |
152 | cmdDir.Flags().Bool("wildcard", false, "Force continued operation when wildcard found") | |
153 | 153 | cmdDir.Flags().BoolP("discover-backup", "d", false, "Upon finding a file search for backup files") |
154 | 154 | cmdDir.Flags().IntSlice("exclude-length", []int{}, "exclude the following content length (completely ignores the status). Supply multiple times to exclude multiple sizes.") |
155 | 155 |
2 | 2 | import ( |
3 | 3 | "context" |
4 | 4 | "fmt" |
5 | "io/ioutil" | |
5 | "io" | |
6 | 6 | "log" |
7 | 7 | "net/http" |
8 | 8 | "net/http/httptest" |
30 | 30 | pluginopts := gobusterdir.NewOptionsDir() |
31 | 31 | pluginopts.URL = h.URL |
32 | 32 | pluginopts.Timeout = 10 * time.Second |
33 | pluginopts.WildcardForced = true | |
34 | 33 | |
35 | 34 | pluginopts.Extensions = ".php,.csv" |
36 | 35 | tmpExt, err := helper.ParseExtensions(pluginopts.Extensions) |
46 | 45 | } |
47 | 46 | pluginopts.StatusCodesParsed = tmpStat |
48 | 47 | |
49 | wordlist, err := ioutil.TempFile("", "") | |
48 | wordlist, err := os.CreateTemp("", "") | |
50 | 49 | if err != nil { |
51 | 50 | b.Fatalf("could not create tempfile: %v", err) |
52 | 51 | } |
72 | 71 | } |
73 | 72 | defer devnull.Close() |
74 | 73 | log.SetFlags(0) |
75 | log.SetOutput(ioutil.Discard) | |
74 | log.SetOutput(io.Discard) | |
76 | 75 | |
77 | 76 | // Run the real benchmark |
78 | 77 | for x := 0; x < b.N; x++ { |
79 | 78 | os.Stdout = devnull |
80 | 79 | os.Stderr = devnull |
81 | plugin, err := gobusterdir.NewGobusterDir(ctx, &globalopts, pluginopts) | |
80 | plugin, err := gobusterdir.NewGobusterDir(&globalopts, pluginopts) | |
82 | 81 | if err != nil { |
83 | 82 | b.Fatalf("error on creating gobusterdir: %v", err) |
84 | 83 | } |
0 | 0 | package cmd |
1 | 1 | |
2 | 2 | import ( |
3 | "errors" | |
3 | 4 | "fmt" |
4 | 5 | "log" |
5 | 6 | "runtime" |
11 | 12 | "github.com/spf13/cobra" |
12 | 13 | ) |
13 | 14 | |
15 | // nolint:gochecknoglobals | |
14 | 16 | var cmdDNS *cobra.Command |
15 | 17 | |
16 | 18 | func runDNS(cmd *cobra.Command, args []string) error { |
25 | 27 | } |
26 | 28 | |
27 | 29 | if err := cli.Gobuster(mainContext, globalopts, plugin); err != nil { |
28 | if goberr, ok := err.(*gobusterdns.ErrWildcard); ok { | |
29 | return fmt.Errorf("%s. To force processing of Wildcard DNS, specify the '--wildcard' switch", goberr.Error()) | |
30 | var wErr *gobusterdns.ErrWildcard | |
31 | if errors.As(err, &wErr) { | |
32 | return fmt.Errorf("%w. To force processing of Wildcard DNS, specify the '--wildcard' switch", wErr) | |
30 | 33 | } |
31 | 34 | return fmt.Errorf("error on running gobuster: %w", err) |
32 | 35 | } |
77 | 80 | return globalopts, plugin, nil |
78 | 81 | } |
79 | 82 | |
83 | // nolint:gochecknoinits | |
80 | 84 | func init() { |
81 | 85 | cmdDNS = &cobra.Command{ |
82 | 86 | Use: "dns", |
0 | 0 | package cmd |
1 | 1 | |
2 | 2 | import ( |
3 | "errors" | |
3 | 4 | "fmt" |
4 | 5 | "log" |
5 | 6 | |
10 | 11 | "github.com/spf13/cobra" |
11 | 12 | ) |
12 | 13 | |
14 | // nolint:gochecknoglobals | |
13 | 15 | var cmdFuzz *cobra.Command |
14 | 16 | |
15 | 17 | func runFuzz(cmd *cobra.Command, args []string) error { |
18 | 20 | return fmt.Errorf("error on parsing arguments: %w", err) |
19 | 21 | } |
20 | 22 | |
21 | plugin, err := gobusterfuzz.NewGobusterFuzz(mainContext, globalopts, pluginopts) | |
23 | plugin, err := gobusterfuzz.NewGobusterFuzz(globalopts, pluginopts) | |
22 | 24 | if err != nil { |
23 | 25 | return fmt.Errorf("error on creating gobusterfuzz: %w", err) |
24 | 26 | } |
25 | 27 | |
26 | 28 | if err := cli.Gobuster(mainContext, globalopts, plugin); err != nil { |
27 | if goberr, ok := err.(*gobusterfuzz.ErrWildcard); ok { | |
28 | return fmt.Errorf("%s. To force processing of Wildcard responses, specify the '--wildcard' switch", goberr.Error()) | |
29 | var wErr *gobusterfuzz.ErrWildcard | |
30 | if errors.As(err, &wErr) { | |
31 | return fmt.Errorf("%w. To continue please exclude the status code or the length", wErr) | |
29 | 32 | } |
30 | 33 | return fmt.Errorf("error on running gobuster: %w", err) |
31 | 34 | } |
56 | 59 | plugin.Headers = httpOpts.Headers |
57 | 60 | plugin.Method = httpOpts.Method |
58 | 61 | |
62 | // blacklist will override the normal status codes | |
59 | 63 | plugin.ExcludedStatusCodes, err = cmdFuzz.Flags().GetString("excludestatuscodes") |
60 | 64 | if err != nil { |
61 | 65 | return nil, nil, fmt.Errorf("invalid value for excludestatuscodes: %w", err) |
62 | 66 | } |
63 | ||
64 | // blacklist will override the normal status codes | |
65 | if plugin.ExcludedStatusCodes != "" { | |
66 | ret, err := helper.ParseCommaSeparatedInt(plugin.ExcludedStatusCodes) | |
67 | if err != nil { | |
68 | return nil, nil, fmt.Errorf("invalid value for excludestatuscodes: %w", err) | |
69 | } | |
70 | plugin.ExcludedStatusCodesParsed = ret | |
67 | ret, err := helper.ParseCommaSeparatedInt(plugin.ExcludedStatusCodes) | |
68 | if err != nil { | |
69 | return nil, nil, fmt.Errorf("invalid value for excludestatuscodes: %w", err) | |
71 | 70 | } |
72 | ||
73 | plugin.WildcardForced, err = cmdFuzz.Flags().GetBool("wildcard") | |
74 | if err != nil { | |
75 | return nil, nil, fmt.Errorf("invalid value for wildcard: %w", err) | |
76 | } | |
71 | plugin.ExcludedStatusCodesParsed = ret | |
77 | 72 | |
78 | 73 | plugin.ExcludeLength, err = cmdFuzz.Flags().GetIntSlice("exclude-length") |
79 | 74 | if err != nil { |
83 | 78 | return globalopts, plugin, nil |
84 | 79 | } |
85 | 80 | |
81 | // nolint:gochecknoinits | |
86 | 82 | func init() { |
87 | 83 | cmdFuzz = &cobra.Command{ |
88 | 84 | Use: "fuzz", |
95 | 91 | } |
96 | 92 | cmdFuzz.Flags().StringP("excludestatuscodes", "b", "", "Negative status codes (will override statuscodes if set)") |
97 | 93 | cmdFuzz.Flags().IntSlice("exclude-length", []int{}, "exclude the following content length (completely ignores the status). Supply multiple times to exclude multiple sizes.") |
98 | cmdFuzz.Flags().BoolP("wildcard", "", false, "Force continued operation when wildcard found") | |
99 | 94 | |
100 | 95 | cmdFuzz.PersistentPreRun = func(cmd *cobra.Command, args []string) { |
101 | 96 | configureGlobalOptions() |
10 | 10 | "github.com/OJ/gobuster/v3/helper" |
11 | 11 | "github.com/OJ/gobuster/v3/libgobuster" |
12 | 12 | "github.com/spf13/cobra" |
13 | "golang.org/x/crypto/ssh/terminal" | |
13 | "golang.org/x/term" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | func addBasicHTTPOptions(cmd *cobra.Command) { |
18 | 18 | cmd.Flags().BoolP("random-agent", "", false, "Use a random User-Agent string") |
19 | 19 | cmd.Flags().StringP("proxy", "", "", "Proxy to use for requests [http(s)://host:port]") |
20 | 20 | cmd.Flags().DurationP("timeout", "", 10*time.Second, "HTTP Timeout") |
21 | cmd.Flags().BoolP("no-tls-validation", "k", false, "Skip TLS certificate verification") | |
21 | 22 | } |
22 | 23 | |
23 | 24 | func addCommonHTTPOptions(cmd *cobra.Command) error { |
27 | 28 | cmd.Flags().StringP("username", "U", "", "Username for Basic Auth") |
28 | 29 | cmd.Flags().StringP("password", "P", "", "Password for Basic Auth") |
29 | 30 | cmd.Flags().BoolP("follow-redirect", "r", false, "Follow redirects") |
30 | cmd.Flags().BoolP("no-tls-validation", "k", false, "Skip TLS certificate verification") | |
31 | 31 | cmd.Flags().StringArrayP("headers", "H", []string{""}, "Specify HTTP headers, -H 'Header1: val1' -H 'Header2: val2'") |
32 | 32 | cmd.Flags().StringP("method", "m", "GET", "Use the following HTTP method") |
33 | 33 | |
51 | 51 | return options, fmt.Errorf("invalid value for random-agent: %w", err) |
52 | 52 | } |
53 | 53 | if randomUA { |
54 | options.UserAgent = helper.GetRandomUserAgent() | |
54 | ua, err := helper.GetRandomUserAgent() | |
55 | if err != nil { | |
56 | return options, err | |
57 | } | |
58 | options.UserAgent = ua | |
55 | 59 | } |
56 | 60 | |
57 | 61 | options.Proxy, err = cmd.Flags().GetString("proxy") |
62 | 66 | options.Timeout, err = cmd.Flags().GetDuration("timeout") |
63 | 67 | if err != nil { |
64 | 68 | return options, fmt.Errorf("invalid value for timeout: %w", err) |
69 | } | |
70 | ||
71 | options.NoTLSValidation, err = cmd.Flags().GetBool("no-tls-validation") | |
72 | if err != nil { | |
73 | return options, fmt.Errorf("invalid value for no-tls-validation: %w", err) | |
65 | 74 | } |
66 | 75 | return options, nil |
67 | 76 | } |
77 | 86 | options.Proxy = basic.Proxy |
78 | 87 | options.Timeout = basic.Timeout |
79 | 88 | options.UserAgent = basic.UserAgent |
89 | options.NoTLSValidation = basic.NoTLSValidation | |
80 | 90 | |
81 | 91 | options.URL, err = cmd.Flags().GetString("url") |
82 | 92 | if err != nil { |
123 | 133 | return options, fmt.Errorf("invalid value for follow-redirect: %w", err) |
124 | 134 | } |
125 | 135 | |
126 | options.NoTLSValidation, err = cmd.Flags().GetBool("no-tls-validation") | |
127 | if err != nil { | |
128 | return options, fmt.Errorf("invalid value for no-tls-validation: %w", err) | |
129 | } | |
130 | ||
131 | 136 | options.Method, err = cmd.Flags().GetString("method") |
132 | 137 | if err != nil { |
133 | 138 | return options, fmt.Errorf("invalid value for method: %w", err) |
156 | 161 | if options.Username != "" && options.Password == "" { |
157 | 162 | fmt.Printf("[?] Auth Password: ") |
158 | 163 | // please don't remove the int cast here as it is sadly needed on windows :/ |
159 | passBytes, err := terminal.ReadPassword(int(syscall.Stdin)) //nolint:unconvert | |
164 | passBytes, err := term.ReadPassword(int(syscall.Stdin)) //nolint:unconvert | |
160 | 165 | // print a newline to simulate the newline that was entered |
161 | 166 | // this means that formatting/printing after doesn't look bad. |
162 | 167 | fmt.Println("") |
8 | 8 | "os/signal" |
9 | 9 | |
10 | 10 | "github.com/OJ/gobuster/v3/libgobuster" |
11 | ||
12 | 11 | "github.com/spf13/cobra" |
13 | 12 | ) |
14 | 13 | |
14 | // nolint:gochecknoglobals | |
15 | 15 | var rootCmd = &cobra.Command{ |
16 | 16 | Use: "gobuster", |
17 | 17 | SilenceUsage: true, |
18 | 18 | } |
19 | 19 | |
20 | // nolint:gochecknoglobals | |
20 | 21 | var mainContext context.Context |
21 | 22 | |
22 | 23 | // Execute is the main cobra method |
46 | 47 | // Once before and once after the help output. Not sure if |
47 | 48 | // this is going to be needed to output other errors that |
48 | 49 | // aren't automatically outputted. |
49 | //fmt.Println(err) | |
50 | // fmt.Println(err) | |
50 | 51 | os.Exit(1) |
51 | 52 | } |
52 | 53 | } |
147 | 148 | } |
148 | 149 | } |
149 | 150 | |
151 | // nolint:gochecknoinits | |
150 | 152 | func init() { |
151 | 153 | rootCmd.PersistentFlags().DurationP("delay", "", 0, "Time each thread waits between requests (e.g. 1500ms)") |
152 | 154 | rootCmd.PersistentFlags().IntP("threads", "t", 10, "Number of concurrent threads") |
8 | 8 | "github.com/spf13/cobra" |
9 | 9 | ) |
10 | 10 | |
11 | // nolint:gochecknoglobals | |
11 | 12 | var cmdS3 *cobra.Command |
12 | 13 | |
13 | 14 | func runS3(cmd *cobra.Command, args []string) error { |
16 | 17 | return fmt.Errorf("error on parsing arguments: %w", err) |
17 | 18 | } |
18 | 19 | |
19 | plugin, err := gobusters3.NewGobusterS3(mainContext, globalopts, pluginopts) | |
20 | plugin, err := gobusters3.NewGobusterS3(globalopts, pluginopts) | |
20 | 21 | if err != nil { |
21 | 22 | return fmt.Errorf("error on creating gobusters3: %w", err) |
22 | 23 | } |
43 | 44 | plugin.UserAgent = httpOpts.UserAgent |
44 | 45 | plugin.Proxy = httpOpts.Proxy |
45 | 46 | plugin.Timeout = httpOpts.Timeout |
47 | plugin.NoTLSValidation = httpOpts.NoTLSValidation | |
46 | 48 | |
47 | 49 | plugin.MaxFilesToList, err = cmdS3.Flags().GetInt("maxfiles") |
48 | 50 | if err != nil { |
52 | 54 | return globalopts, plugin, nil |
53 | 55 | } |
54 | 56 | |
57 | // nolint:gochecknoinits | |
55 | 58 | func init() { |
56 | 59 | cmdS3 = &cobra.Command{ |
57 | 60 | Use: "s3", |
6 | 6 | "github.com/spf13/cobra" |
7 | 7 | ) |
8 | 8 | |
9 | // nolint:gochecknoglobals | |
9 | 10 | var cmdVersion *cobra.Command |
10 | 11 | |
11 | 12 | func runVersion(cmd *cobra.Command, args []string) error { |
13 | 14 | return nil |
14 | 15 | } |
15 | 16 | |
17 | // nolint:gochecknoinits | |
16 | 18 | func init() { |
17 | 19 | cmdVersion = &cobra.Command{ |
18 | 20 | Use: "version", |
9 | 9 | "github.com/spf13/cobra" |
10 | 10 | ) |
11 | 11 | |
12 | // nolint:gochecknoglobals | |
12 | 13 | var cmdVhost *cobra.Command |
13 | 14 | |
14 | 15 | func runVhost(cmd *cobra.Command, args []string) error { |
17 | 18 | return fmt.Errorf("error on parsing arguments: %w", err) |
18 | 19 | } |
19 | 20 | |
20 | plugin, err := gobustervhost.NewGobusterVhost(mainContext, globalopts, pluginopts) | |
21 | plugin, err := gobustervhost.NewGobusterVhost(globalopts, pluginopts) | |
21 | 22 | if err != nil { |
22 | 23 | return fmt.Errorf("error on creating gobustervhost: %w", err) |
23 | 24 | } |
51 | 52 | plugin.Headers = httpOpts.Headers |
52 | 53 | plugin.Method = httpOpts.Method |
53 | 54 | |
55 | plugin.AppendDomain, err = cmdVhost.Flags().GetBool("append-domain") | |
56 | if err != nil { | |
57 | return nil, nil, fmt.Errorf("invalid value for append-domain: %w", err) | |
58 | } | |
59 | ||
60 | plugin.ExcludeLength, err = cmdVhost.Flags().GetIntSlice("exclude-length") | |
61 | if err != nil { | |
62 | return nil, nil, fmt.Errorf("invalid value for excludelength: %w", err) | |
63 | } | |
64 | ||
65 | plugin.Domain, err = cmdVhost.Flags().GetString("domain") | |
66 | if err != nil { | |
67 | return nil, nil, fmt.Errorf("invalid value for domain: %w", err) | |
68 | } | |
69 | ||
54 | 70 | return globalopts, &plugin, nil |
55 | 71 | } |
56 | 72 | |
73 | // nolint:gochecknoinits | |
57 | 74 | func init() { |
58 | 75 | cmdVhost = &cobra.Command{ |
59 | 76 | Use: "vhost", |
60 | Short: "Uses VHOST enumeration mode", | |
77 | Short: "Uses VHOST enumeration mode (you most probably want to use the IP adress as the URL parameter", | |
61 | 78 | RunE: runVhost, |
62 | 79 | } |
63 | 80 | if err := addCommonHTTPOptions(cmdVhost); err != nil { |
64 | 81 | log.Fatalf("%v", err) |
65 | 82 | } |
83 | cmdVhost.Flags().BoolP("append-domain", "", false, "Append main domain from URL to words from wordlist. Otherwise the fully qualified domains need to be specified in the wordlist.") | |
84 | cmdVhost.Flags().IntSlice("exclude-length", []int{}, "exclude the following content length (completely ignores the status). Supply multiple times to exclude multiple sizes.") | |
85 | cmdVhost.Flags().String("domain", "", "the domain to append when using an IP address as URL. If left empty and you specify a domain based URL the hostname from the URL is extracted") | |
66 | 86 | |
67 | 87 | cmdVhost.PersistentPreRun = func(cmd *cobra.Command, args []string) { |
68 | 88 | configureGlobalOptions() |
2 | 2 | import ( |
3 | 3 | "context" |
4 | 4 | "fmt" |
5 | "io/ioutil" | |
5 | "io" | |
6 | 6 | "log" |
7 | 7 | "os" |
8 | 8 | "testing" |
21 | 21 | pluginopts.URL = h.URL |
22 | 22 | pluginopts.Timeout = 10 * time.Second |
23 | 23 | |
24 | wordlist, err := ioutil.TempFile("", "") | |
24 | wordlist, err := os.CreateTemp("", "") | |
25 | 25 | if err != nil { |
26 | 26 | b.Fatalf("could not create tempfile: %v", err) |
27 | 27 | } |
47 | 47 | } |
48 | 48 | defer devnull.Close() |
49 | 49 | log.SetFlags(0) |
50 | log.SetOutput(ioutil.Discard) | |
50 | log.SetOutput(io.Discard) | |
51 | 51 | |
52 | 52 | // Run the real benchmark |
53 | 53 | for x := 0; x < b.N; x++ { |
54 | 54 | os.Stdout = devnull |
55 | 55 | os.Stderr = devnull |
56 | plugin, err := gobustervhost.NewGobusterVhost(ctx, &globalopts, &pluginopts) | |
56 | plugin, err := gobustervhost.NewGobusterVhost(&globalopts, &pluginopts) | |
57 | 57 | if err != nil { |
58 | 58 | b.Fatalf("error on creating gobusterdir: %v", err) |
59 | 59 | } |
91 | 91 | |
92 | 92 | // progressWorker outputs the progress every tick. It will stop once cancel() is called |
93 | 93 | // on the context |
94 | func progressWorker(c context.Context, g *libgobuster.Gobuster, wg *sync.WaitGroup, output *outputType) { | |
94 | func progressWorker(ctx context.Context, g *libgobuster.Gobuster, wg *sync.WaitGroup, output *outputType) { | |
95 | 95 | defer wg.Done() |
96 | 96 | |
97 | 97 | tick := time.NewTicker(cliProgressUpdate) |
120 | 120 | output.Mu.Unlock() |
121 | 121 | g.RequestsCountMutex.RUnlock() |
122 | 122 | } |
123 | case <-c.Done(): | |
123 | case <-ctx.Done(): | |
124 | 124 | return |
125 | 125 | } |
126 | 126 | } |
135 | 135 | } |
136 | 136 | |
137 | 137 | // Gobuster is the main entry point for the CLI |
138 | func Gobuster(prevCtx context.Context, opts *libgobuster.Options, plugin libgobuster.GobusterPlugin) error { | |
138 | func Gobuster(ctx context.Context, opts *libgobuster.Options, plugin libgobuster.GobusterPlugin) error { | |
139 | 139 | // Sanity checks |
140 | 140 | if opts == nil { |
141 | 141 | return fmt.Errorf("please provide valid options") |
145 | 145 | return fmt.Errorf("please provide a valid plugin") |
146 | 146 | } |
147 | 147 | |
148 | ctx, cancel := context.WithCancel(prevCtx) | |
148 | ctxCancel, cancel := context.WithCancel(ctx) | |
149 | 149 | defer cancel() |
150 | 150 | |
151 | gobuster, err := libgobuster.NewGobuster(ctx, opts, plugin) | |
151 | gobuster, err := libgobuster.NewGobuster(opts, plugin) | |
152 | 152 | if err != nil { |
153 | 153 | return err |
154 | 154 | } |
187 | 187 | if !opts.Quiet && !opts.NoProgress { |
188 | 188 | // if not quiet add a new workgroup entry and start the goroutine |
189 | 189 | wg.Add(1) |
190 | go progressWorker(ctx, gobuster, &wg, o) | |
191 | } | |
192 | ||
193 | err = gobuster.Start() | |
190 | go progressWorker(ctxCancel, gobuster, &wg, o) | |
191 | } | |
192 | ||
193 | err = gobuster.Run(ctxCancel) | |
194 | 194 | |
195 | 195 | // call cancel func so progressWorker will exit (the only goroutine in this |
196 | 196 | // file using the context) and to free resources |
0 | gobuster (3.1.0+git20220910.1.9ea1da4-0kali1) UNRELEASED; urgency=low | |
1 | ||
2 | * New upstream snapshot. | |
3 | ||
4 | -- Kali Janitor <[email protected]> Wed, 28 Sep 2022 16:25:34 -0000 | |
5 | ||
0 | 6 | gobuster (3.1.0-0kali1) kali-dev; urgency=medium |
1 | 7 | |
2 | 8 | * Remove useless patches |
0 | 0 | module github.com/OJ/gobuster/v3 |
1 | 1 | |
2 | 2 | require ( |
3 | github.com/google/uuid v1.1.1 | |
4 | github.com/spf13/cobra v1.0.0 | |
5 | github.com/spf13/pflag v1.0.5 // indirect | |
6 | golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de | |
7 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed // indirect | |
3 | github.com/google/uuid v1.3.0 | |
4 | github.com/spf13/cobra v1.5.0 | |
5 | golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 | |
8 | 6 | ) |
9 | 7 | |
10 | go 1.15 | |
8 | require ( | |
9 | github.com/inconshreveable/mousetrap v1.0.1 // indirect | |
10 | github.com/spf13/pflag v1.0.5 // indirect | |
11 | golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 // indirect | |
12 | ) | |
13 | ||
14 | go 1.17 |
0 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | |
1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | |
2 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= | |
3 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | |
4 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | |
5 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= | |
6 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | |
7 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= | |
8 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= | |
9 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | |
10 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= | |
11 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= | |
12 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | |
13 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | |
14 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= | |
15 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | |
16 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |
17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
18 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | |
19 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= | |
20 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |
21 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | |
22 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= | |
23 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= | |
24 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= | |
25 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= | |
26 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | |
27 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | |
28 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | |
29 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | |
30 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |
31 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |
32 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |
33 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | |
34 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | |
35 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= | |
36 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |
37 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | |
38 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= | |
39 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= | |
40 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= | |
41 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= | |
42 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= | |
0 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | |
1 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | |
2 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |
43 | 3 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
44 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= | |
45 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= | |
46 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | |
47 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | |
48 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | |
49 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= | |
50 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | |
51 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | |
52 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | |
53 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | |
54 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | |
55 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | |
56 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | |
57 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | |
58 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= | |
59 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= | |
60 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |
61 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |
62 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
63 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= | |
64 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= | |
65 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | |
66 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | |
67 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= | |
68 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | |
69 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | |
70 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | |
71 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= | |
72 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | |
73 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | |
74 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | |
75 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | |
76 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | |
77 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= | |
78 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= | |
79 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= | |
80 | github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= | |
81 | github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= | |
82 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= | |
83 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= | |
84 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | |
4 | github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= | |
5 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | |
6 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | |
7 | github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= | |
8 | github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= | |
85 | 9 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= |
86 | 10 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= |
87 | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= | |
88 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |
89 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | |
90 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | |
91 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= | |
92 | github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= | |
93 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= | |
94 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= | |
95 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | |
96 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | |
97 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= | |
98 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= | |
99 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | |
100 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |
101 | golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= | |
102 | golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |
103 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | |
104 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | |
105 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |
106 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |
107 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |
108 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |
109 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= | |
110 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |
111 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | |
112 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |
113 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
114 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
115 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
116 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
117 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
118 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
119 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
120 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
121 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
122 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed h1:WBkVNH1zd9jg/dK4HCM4lNANnmd12EHC9z+LmcCG4ns= | |
123 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
124 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | |
125 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |
126 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |
127 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |
128 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |
129 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |
130 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | |
131 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | |
132 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | |
133 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | |
134 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | |
11 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |
12 | golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 h1:wM1k/lXfpc5HdkJJyW9GELpd8ERGdnh8sMGL6Gzq3Ho= | |
13 | golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |
14 | golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc= | |
15 | golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | |
135 | 16 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
136 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
137 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= | |
138 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= | |
139 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |
140 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |
141 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |
17 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
39 | 39 | } |
40 | 40 | |
41 | 41 | // NewGobusterDir creates a new initialized GobusterDir |
42 | func NewGobusterDir(cont context.Context, globalopts *libgobuster.Options, opts *OptionsDir) (*GobusterDir, error) { | |
42 | func NewGobusterDir(globalopts *libgobuster.Options, opts *OptionsDir) (*GobusterDir, error) { | |
43 | 43 | if globalopts == nil { |
44 | 44 | return nil, fmt.Errorf("please provide valid global options") |
45 | 45 | } |
54 | 54 | } |
55 | 55 | |
56 | 56 | basicOptions := libgobuster.BasicHTTPOptions{ |
57 | Proxy: opts.Proxy, | |
58 | Timeout: opts.Timeout, | |
59 | UserAgent: opts.UserAgent, | |
57 | Proxy: opts.Proxy, | |
58 | Timeout: opts.Timeout, | |
59 | UserAgent: opts.UserAgent, | |
60 | NoTLSValidation: opts.NoTLSValidation, | |
60 | 61 | } |
61 | 62 | |
62 | 63 | httpOpts := libgobuster.HTTPOptions{ |
63 | 64 | BasicHTTPOptions: basicOptions, |
64 | 65 | FollowRedirect: opts.FollowRedirect, |
65 | NoTLSValidation: opts.NoTLSValidation, | |
66 | 66 | Username: opts.Username, |
67 | 67 | Password: opts.Password, |
68 | 68 | Headers: opts.Headers, |
70 | 70 | Method: opts.Method, |
71 | 71 | } |
72 | 72 | |
73 | h, err := libgobuster.NewHTTPClient(cont, &httpOpts) | |
73 | h, err := libgobuster.NewHTTPClient(&httpOpts) | |
74 | 74 | if err != nil { |
75 | 75 | return nil, err |
76 | 76 | } |
105 | 105 | } |
106 | 106 | |
107 | 107 | // PreRun is the pre run implementation of gobusterdir |
108 | func (d *GobusterDir) PreRun() error { | |
108 | func (d *GobusterDir) PreRun(ctx context.Context) error { | |
109 | 109 | // add trailing slash |
110 | 110 | if !strings.HasSuffix(d.options.URL, "/") { |
111 | 111 | d.options.URL = fmt.Sprintf("%s/", d.options.URL) |
112 | 112 | } |
113 | 113 | |
114 | _, _, _, _, err := d.http.Request(d.options.URL, libgobuster.RequestOptions{}) | |
114 | _, _, _, _, err := d.http.Request(ctx, d.options.URL, libgobuster.RequestOptions{}) | |
115 | 115 | if err != nil { |
116 | 116 | return fmt.Errorf("unable to connect to %s: %w", d.options.URL, err) |
117 | 117 | } |
122 | 122 | url = fmt.Sprintf("%s/", url) |
123 | 123 | } |
124 | 124 | |
125 | wildcardResp, wildcardLength, _, _, err := d.http.Request(url, libgobuster.RequestOptions{}) | |
125 | wildcardResp, wildcardLength, _, _, err := d.http.Request(ctx, url, libgobuster.RequestOptions{}) | |
126 | 126 | if err != nil { |
127 | 127 | return err |
128 | 128 | } |
133 | 133 | } |
134 | 134 | |
135 | 135 | if d.options.StatusCodesBlacklistParsed.Length() > 0 { |
136 | if !d.options.StatusCodesBlacklistParsed.Contains(*wildcardResp) && !d.options.WildcardForced { | |
136 | if !d.options.StatusCodesBlacklistParsed.Contains(*wildcardResp) { | |
137 | 137 | return &ErrWildcard{url: url, statusCode: *wildcardResp, length: wildcardLength} |
138 | 138 | } |
139 | 139 | } else if d.options.StatusCodesParsed.Length() > 0 { |
140 | if d.options.StatusCodesParsed.Contains(*wildcardResp) && !d.options.WildcardForced { | |
140 | if d.options.StatusCodesParsed.Contains(*wildcardResp) { | |
141 | 141 | return &ErrWildcard{url: url, statusCode: *wildcardResp, length: wildcardLength} |
142 | 142 | } |
143 | 143 | } else { |
163 | 163 | } |
164 | 164 | |
165 | 165 | // Run is the process implementation of gobusterdir |
166 | func (d *GobusterDir) Run(word string, resChannel chan<- libgobuster.Result) error { | |
166 | func (d *GobusterDir) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { | |
167 | 167 | suffix := "" |
168 | 168 | if d.options.UseSlash { |
169 | 169 | suffix = "/" |
196 | 196 | } |
197 | 197 | |
198 | 198 | for entity, url := range urlsToCheck { |
199 | statusCode, size, header, _, err := d.http.Request(url, libgobuster.RequestOptions{}) | |
199 | statusCode, size, header, _, err := d.http.Request(ctx, url, libgobuster.RequestOptions{}) | |
200 | 200 | if err != nil { |
201 | 201 | return err |
202 | 202 | } |
13 | 13 | StatusCodesBlacklist string |
14 | 14 | StatusCodesBlacklistParsed libgobuster.IntSet |
15 | 15 | UseSlash bool |
16 | WildcardForced bool | |
17 | 16 | HideLength bool |
18 | 17 | Expanded bool |
19 | 18 | NoStatus bool |
19 | 19 | Size int64 |
20 | 20 | } |
21 | 21 | |
22 | // ToString converts the Result to it's textual representation | |
22 | // ResultToString converts the Result to it's textual representation | |
23 | 23 | func (r Result) ResultToString() (string, error) { |
24 | 24 | buf := &bytes.Buffer{} |
25 | 25 |
81 | 81 | } |
82 | 82 | |
83 | 83 | // PreRun is the pre run implementation of gobusterdns |
84 | func (d *GobusterDNS) PreRun() error { | |
84 | func (d *GobusterDNS) PreRun(ctx context.Context) error { | |
85 | 85 | // Resolve a subdomain that probably shouldn't exist |
86 | 86 | guid := uuid.New() |
87 | wildcardIps, err := d.dnsLookup(fmt.Sprintf("%s.%s", guid, d.options.Domain)) | |
87 | wildcardIps, err := d.dnsLookup(ctx, fmt.Sprintf("%s.%s", guid, d.options.Domain)) | |
88 | 88 | if err == nil { |
89 | 89 | d.isWildcard = true |
90 | 90 | d.wildcardIps.AddRange(wildcardIps) |
95 | 95 | |
96 | 96 | if !d.globalopts.Quiet { |
97 | 97 | // Provide a warning if the base domain doesn't resolve (in case of typo) |
98 | _, err = d.dnsLookup(d.options.Domain) | |
98 | _, err = d.dnsLookup(ctx, d.options.Domain) | |
99 | 99 | if err != nil { |
100 | 100 | // Not an error, just a warning. Eg. `yp.to` doesn't resolve, but `cr.yp.to` does! |
101 | 101 | log.Printf("[-] Unable to validate base domain: %s (%v)", d.options.Domain, err) |
106 | 106 | } |
107 | 107 | |
108 | 108 | // Run is the process implementation of gobusterdns |
109 | func (d *GobusterDNS) Run(word string, resChannel chan<- libgobuster.Result) error { | |
109 | func (d *GobusterDNS) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { | |
110 | 110 | subdomain := fmt.Sprintf("%s.%s", word, d.options.Domain) |
111 | ips, err := d.dnsLookup(subdomain) | |
111 | ips, err := d.dnsLookup(ctx, subdomain) | |
112 | 112 | if err == nil { |
113 | 113 | if !d.isWildcard || !d.wildcardIps.ContainsAny(ips) { |
114 | 114 | result := Result{ |
120 | 120 | if d.options.ShowIPs { |
121 | 121 | result.IPs = ips |
122 | 122 | } else if d.options.ShowCNAME { |
123 | cname, err := d.dnsLookupCname(subdomain) | |
123 | cname, err := d.dnsLookupCname(ctx, subdomain) | |
124 | 124 | if err == nil { |
125 | 125 | result.CNAME = cname |
126 | 126 | } |
218 | 218 | return strings.TrimSpace(buffer.String()), nil |
219 | 219 | } |
220 | 220 | |
221 | func (d *GobusterDNS) dnsLookup(domain string) ([]string, error) { | |
222 | ctx, cancel := context.WithTimeout(context.Background(), d.options.Timeout) | |
221 | func (d *GobusterDNS) dnsLookup(ctx context.Context, domain string) ([]string, error) { | |
222 | ctx2, cancel := context.WithTimeout(ctx, d.options.Timeout) | |
223 | 223 | defer cancel() |
224 | return d.resolver.LookupHost(ctx, domain) | |
225 | } | |
226 | ||
227 | func (d *GobusterDNS) dnsLookupCname(domain string) (string, error) { | |
228 | ctx, cancel := context.WithTimeout(context.Background(), d.options.Timeout) | |
224 | return d.resolver.LookupHost(ctx2, domain) | |
225 | } | |
226 | ||
227 | func (d *GobusterDNS) dnsLookupCname(ctx context.Context, domain string) (string, error) { | |
228 | ctx2, cancel := context.WithTimeout(ctx, d.options.Timeout) | |
229 | 229 | defer cancel() |
230 | 230 | time.Sleep(time.Second) |
231 | return d.resolver.LookupCNAME(ctx, domain) | |
232 | } | |
231 | return d.resolver.LookupCNAME(ctx2, domain) | |
232 | } |
15 | 15 | CNAME string |
16 | 16 | } |
17 | 17 | |
18 | // ToString converts the Result to it's textual representation | |
18 | // ResultToString converts the Result to it's textual representation | |
19 | 19 | func (r Result) ResultToString() (string, error) { |
20 | 20 | buf := &bytes.Buffer{} |
21 | 21 |
30 | 30 | } |
31 | 31 | |
32 | 32 | // NewGobusterFuzz creates a new initialized GobusterFuzz |
33 | func NewGobusterFuzz(cont context.Context, globalopts *libgobuster.Options, opts *OptionsFuzz) (*GobusterFuzz, error) { | |
33 | func NewGobusterFuzz(globalopts *libgobuster.Options, opts *OptionsFuzz) (*GobusterFuzz, error) { | |
34 | 34 | if globalopts == nil { |
35 | 35 | return nil, fmt.Errorf("please provide valid global options") |
36 | 36 | } |
45 | 45 | } |
46 | 46 | |
47 | 47 | basicOptions := libgobuster.BasicHTTPOptions{ |
48 | Proxy: opts.Proxy, | |
49 | Timeout: opts.Timeout, | |
50 | UserAgent: opts.UserAgent, | |
48 | Proxy: opts.Proxy, | |
49 | Timeout: opts.Timeout, | |
50 | UserAgent: opts.UserAgent, | |
51 | NoTLSValidation: opts.NoTLSValidation, | |
51 | 52 | } |
52 | 53 | |
53 | 54 | httpOpts := libgobuster.HTTPOptions{ |
54 | 55 | BasicHTTPOptions: basicOptions, |
55 | 56 | FollowRedirect: opts.FollowRedirect, |
56 | NoTLSValidation: opts.NoTLSValidation, | |
57 | 57 | Username: opts.Username, |
58 | 58 | Password: opts.Password, |
59 | 59 | Headers: opts.Headers, |
61 | 61 | Method: opts.Method, |
62 | 62 | } |
63 | 63 | |
64 | h, err := libgobuster.NewHTTPClient(cont, &httpOpts) | |
64 | h, err := libgobuster.NewHTTPClient(&httpOpts) | |
65 | 65 | if err != nil { |
66 | 66 | return nil, err |
67 | 67 | } |
80 | 80 | } |
81 | 81 | |
82 | 82 | // PreRun is the pre run implementation of gobusterfuzz |
83 | func (d *GobusterFuzz) PreRun() error { | |
83 | func (d *GobusterFuzz) PreRun(ctx context.Context) error { | |
84 | 84 | return nil |
85 | 85 | } |
86 | 86 | |
87 | 87 | // Run is the process implementation of gobusterfuzz |
88 | func (d *GobusterFuzz) Run(word string, resChannel chan<- libgobuster.Result) error { | |
88 | func (d *GobusterFuzz) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { | |
89 | 89 | workingURL := strings.ReplaceAll(d.options.URL, "FUZZ", word) |
90 | statusCode, size, _, _, err := d.http.Request(workingURL, libgobuster.RequestOptions{}) | |
90 | statusCode, size, _, _, err := d.http.Request(ctx, workingURL, libgobuster.RequestOptions{}) | |
91 | 91 | if err != nil { |
92 | 92 | return err |
93 | 93 | } |
8 | 8 | libgobuster.HTTPOptions |
9 | 9 | ExcludedStatusCodes string |
10 | 10 | ExcludedStatusCodesParsed libgobuster.IntSet |
11 | WildcardForced bool | |
12 | 11 | ExcludeLength []int |
13 | 12 | } |
14 | 13 |
13 | 13 | Size int64 |
14 | 14 | } |
15 | 15 | |
16 | // ToString converts the Result to it's textual representation | |
16 | // ResultToString converts the Result to it's textual representation | |
17 | 17 | func (r Result) ResultToString() (string, error) { |
18 | 18 | buf := &bytes.Buffer{} |
19 | 19 |
22 | 22 | } |
23 | 23 | |
24 | 24 | // NewGobusterS3 creates a new initialized GobusterS3 |
25 | func NewGobusterS3(cont context.Context, globalopts *libgobuster.Options, opts *OptionsS3) (*GobusterS3, error) { | |
25 | func NewGobusterS3(globalopts *libgobuster.Options, opts *OptionsS3) (*GobusterS3, error) { | |
26 | 26 | if globalopts == nil { |
27 | 27 | return nil, fmt.Errorf("please provide valid global options") |
28 | 28 | } |
37 | 37 | } |
38 | 38 | |
39 | 39 | basicOptions := libgobuster.BasicHTTPOptions{ |
40 | Proxy: opts.Proxy, | |
41 | Timeout: opts.Timeout, | |
42 | UserAgent: opts.UserAgent, | |
40 | Proxy: opts.Proxy, | |
41 | Timeout: opts.Timeout, | |
42 | UserAgent: opts.UserAgent, | |
43 | NoTLSValidation: opts.NoTLSValidation, | |
43 | 44 | } |
44 | 45 | |
45 | 46 | httpOpts := libgobuster.HTTPOptions{ |
48 | 49 | FollowRedirect: true, |
49 | 50 | } |
50 | 51 | |
51 | h, err := libgobuster.NewHTTPClient(cont, &httpOpts) | |
52 | h, err := libgobuster.NewHTTPClient(&httpOpts) | |
52 | 53 | if err != nil { |
53 | 54 | return nil, err |
54 | 55 | } |
69 | 70 | } |
70 | 71 | |
71 | 72 | // PreRun is the pre run implementation of GobusterS3 |
72 | func (s *GobusterS3) PreRun() error { | |
73 | func (s *GobusterS3) PreRun(ctx context.Context) error { | |
73 | 74 | return nil |
74 | 75 | } |
75 | 76 | |
76 | 77 | // Run is the process implementation of GobusterS3 |
77 | func (s *GobusterS3) Run(word string, resChannel chan<- libgobuster.Result) error { | |
78 | func (s *GobusterS3) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { | |
78 | 79 | // only check for valid bucket names |
79 | 80 | if !s.isValidBucketName(word) { |
80 | 81 | return nil |
81 | 82 | } |
82 | 83 | |
83 | bucketURL := fmt.Sprintf("http://%s.s3.amazonaws.com/?max-keys=%d", word, s.options.MaxFilesToList) | |
84 | status, _, _, body, err := s.http.Request(bucketURL, libgobuster.RequestOptions{ReturnBody: true}) | |
84 | bucketURL := fmt.Sprintf("https://%s.s3.amazonaws.com/?max-keys=%d", word, s.options.MaxFilesToList) | |
85 | status, _, _, body, err := s.http.Request(ctx, bucketURL, libgobuster.RequestOptions{ReturnBody: true}) | |
85 | 86 | if err != nil { |
86 | 87 | return err |
87 | 88 | } |
11 | 11 | Status string |
12 | 12 | } |
13 | 13 | |
14 | // ToString converts the Result to it's textual representation | |
14 | // ResultToString converts the Result to it's textual representation | |
15 | 15 | func (r Result) ResultToString() (string, error) { |
16 | 16 | buf := &bytes.Buffer{} |
17 | 17 |
8 | 8 | "strings" |
9 | 9 | "text/tabwriter" |
10 | 10 | |
11 | "github.com/OJ/gobuster/v3/helper" | |
11 | 12 | "github.com/OJ/gobuster/v3/libgobuster" |
12 | 13 | "github.com/google/uuid" |
13 | 14 | ) |
23 | 24 | } |
24 | 25 | |
25 | 26 | // NewGobusterVhost creates a new initialized GobusterDir |
26 | func NewGobusterVhost(cont context.Context, globalopts *libgobuster.Options, opts *OptionsVhost) (*GobusterVhost, error) { | |
27 | func NewGobusterVhost(globalopts *libgobuster.Options, opts *OptionsVhost) (*GobusterVhost, error) { | |
27 | 28 | if globalopts == nil { |
28 | 29 | return nil, fmt.Errorf("please provide valid global options") |
29 | 30 | } |
38 | 39 | } |
39 | 40 | |
40 | 41 | basicOptions := libgobuster.BasicHTTPOptions{ |
41 | Proxy: opts.Proxy, | |
42 | Timeout: opts.Timeout, | |
43 | UserAgent: opts.UserAgent, | |
42 | Proxy: opts.Proxy, | |
43 | Timeout: opts.Timeout, | |
44 | UserAgent: opts.UserAgent, | |
45 | NoTLSValidation: opts.NoTLSValidation, | |
44 | 46 | } |
45 | 47 | |
46 | 48 | httpOpts := libgobuster.HTTPOptions{ |
47 | 49 | BasicHTTPOptions: basicOptions, |
48 | 50 | FollowRedirect: opts.FollowRedirect, |
49 | NoTLSValidation: opts.NoTLSValidation, | |
50 | 51 | Username: opts.Username, |
51 | 52 | Password: opts.Password, |
52 | 53 | Headers: opts.Headers, |
54 | 55 | Method: opts.Method, |
55 | 56 | } |
56 | 57 | |
57 | h, err := libgobuster.NewHTTPClient(cont, &httpOpts) | |
58 | h, err := libgobuster.NewHTTPClient(&httpOpts) | |
58 | 59 | if err != nil { |
59 | 60 | return nil, err |
60 | 61 | } |
73 | 74 | } |
74 | 75 | |
75 | 76 | // PreRun is the pre run implementation of gobusterdir |
76 | func (v *GobusterVhost) PreRun() error { | |
77 | func (v *GobusterVhost) PreRun(ctx context.Context) error { | |
77 | 78 | // add trailing slash |
78 | 79 | if !strings.HasSuffix(v.options.URL, "/") { |
79 | 80 | v.options.URL = fmt.Sprintf("%s/", v.options.URL) |
83 | 84 | if err != nil { |
84 | 85 | return fmt.Errorf("invalid url %s: %w", v.options.URL, err) |
85 | 86 | } |
86 | v.domain = urlParsed.Host | |
87 | if v.options.Domain != "" { | |
88 | v.domain = v.options.Domain | |
89 | } else { | |
90 | v.domain = urlParsed.Host | |
91 | } | |
87 | 92 | |
88 | 93 | // request default vhost for baseline1 |
89 | _, _, _, tmp, err := v.http.Request(v.options.URL, libgobuster.RequestOptions{ReturnBody: true}) | |
94 | _, _, _, tmp, err := v.http.Request(ctx, v.options.URL, libgobuster.RequestOptions{ReturnBody: true}) | |
90 | 95 | if err != nil { |
91 | 96 | return fmt.Errorf("unable to connect to %s: %w", v.options.URL, err) |
92 | 97 | } |
94 | 99 | |
95 | 100 | // request non existent vhost for baseline2 |
96 | 101 | subdomain := fmt.Sprintf("%s.%s", uuid.New(), v.domain) |
97 | _, _, _, tmp, err = v.http.Request(v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) | |
102 | _, _, _, tmp, err = v.http.Request(ctx, v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) | |
98 | 103 | if err != nil { |
99 | 104 | return fmt.Errorf("unable to connect to %s: %w", v.options.URL, err) |
100 | 105 | } |
103 | 108 | } |
104 | 109 | |
105 | 110 | // Run is the process implementation of gobusterdir |
106 | func (v *GobusterVhost) Run(word string, resChannel chan<- libgobuster.Result) error { | |
107 | subdomain := fmt.Sprintf("%s.%s", word, v.domain) | |
108 | status, size, header, body, err := v.http.Request(v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) | |
111 | func (v *GobusterVhost) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { | |
112 | var subdomain string | |
113 | if v.options.AppendDomain { | |
114 | subdomain = fmt.Sprintf("%s.%s", word, v.domain) | |
115 | } else { | |
116 | // wordlist needs to include full domains | |
117 | subdomain = word | |
118 | } | |
119 | status, size, header, body, err := v.http.Request(ctx, v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) | |
109 | 120 | if err != nil { |
110 | 121 | return err |
111 | 122 | } |
113 | 124 | // subdomain must not match default vhost and non existent vhost |
114 | 125 | // or verbose mode is enabled |
115 | 126 | found := !bytes.Equal(body, v.baseline1) && !bytes.Equal(body, v.baseline2) |
116 | if found || v.globalopts.Verbose { | |
127 | if (found && !helper.SliceContains(v.options.ExcludeLength, int(size))) || v.globalopts.Verbose { | |
117 | 128 | resultStatus := false |
118 | 129 | if found { |
119 | 130 | resultStatus = true |
201 | 212 | return "", err |
202 | 213 | } |
203 | 214 | |
215 | if _, err := fmt.Fprintf(tw, "[+] Append Domain:\t%t\n", v.options.AppendDomain); err != nil { | |
216 | return "", err | |
217 | } | |
218 | ||
219 | if len(o.ExcludeLength) > 0 { | |
220 | if _, err := fmt.Fprintf(tw, "[+] Exclude Length:\t%s\n", helper.JoinIntSlice(v.options.ExcludeLength)); err != nil { | |
221 | return "", err | |
222 | } | |
223 | } | |
224 | ||
204 | 225 | if err := tw.Flush(); err != nil { |
205 | 226 | return "", fmt.Errorf("error on tostring: %w", err) |
206 | 227 | } |
6 | 6 | // OptionsVhost is the struct to hold all options for this plugin |
7 | 7 | type OptionsVhost struct { |
8 | 8 | libgobuster.HTTPOptions |
9 | AppendDomain bool | |
10 | ExcludeLength []int | |
11 | Domain string | |
9 | 12 | } |
14 | 14 | Header http.Header |
15 | 15 | } |
16 | 16 | |
17 | // ToString converts the Result to it's textual representation | |
17 | // ResultToString converts the Result to it's textual representation | |
18 | 18 | func (r Result) ResultToString() (string, error) { |
19 | 19 | buf := &bytes.Buffer{} |
20 | 20 |
10 | 10 | // ParseExtensions parses the extensions provided as a comma separated list |
11 | 11 | func ParseExtensions(extensions string) (libgobuster.StringSet, error) { |
12 | 12 | if extensions == "" { |
13 | return libgobuster.StringSet{}, fmt.Errorf("invalid extension string provided") | |
13 | return libgobuster.StringSet{}, nil | |
14 | 14 | } |
15 | 15 | |
16 | 16 | ret := libgobuster.NewStringSet() |
25 | 25 | // ParseCommaSeparatedInt parses the status codes provided as a comma separated list |
26 | 26 | func ParseCommaSeparatedInt(inputString string) (libgobuster.IntSet, error) { |
27 | 27 | if inputString == "" { |
28 | return libgobuster.IntSet{}, fmt.Errorf("invalid string provided") | |
28 | return libgobuster.IntSet{}, nil | |
29 | 29 | } |
30 | 30 | |
31 | 31 | ret := libgobuster.NewIntSet() |
8 | 8 | |
9 | 9 | func TestParseExtensions(t *testing.T) { |
10 | 10 | t.Parallel() |
11 | ||
12 | 11 | var tt = []struct { |
13 | 12 | testName string |
14 | 13 | extensions string |
23 | 22 | } |
24 | 23 | |
25 | 24 | for _, x := range tt { |
25 | x := x // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables | |
26 | 26 | t.Run(x.testName, func(t *testing.T) { |
27 | t.Parallel() | |
27 | 28 | ret, err := ParseExtensions(x.extensions) |
28 | 29 | if x.expectedError != "" { |
29 | 30 | if err != nil && err.Error() != x.expectedError { |
38 | 39 | |
39 | 40 | func TestParseCommaSeparatedInt(t *testing.T) { |
40 | 41 | t.Parallel() |
41 | ||
42 | 42 | var tt = []struct { |
43 | 43 | testName string |
44 | 44 | stringCodes string |
54 | 54 | } |
55 | 55 | |
56 | 56 | for _, x := range tt { |
57 | x := x // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables | |
57 | 58 | t.Run(x.testName, func(t *testing.T) { |
59 | t.Parallel() | |
58 | 60 | ret, err := ParseCommaSeparatedInt(x.stringCodes) |
59 | 61 | if x.expectedError != "" { |
60 | 62 | if err != nil && err.Error() != x.expectedError { |
82 | 84 | } |
83 | 85 | |
84 | 86 | for _, x := range tt { |
87 | x := x // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables | |
85 | 88 | b.Run(x.testName, func(b2 *testing.B) { |
86 | 89 | for y := 0; y < b2.N; y++ { |
87 | 90 | _, _ = ParseExtensions(x.extensions) |
106 | 109 | } |
107 | 110 | |
108 | 111 | for _, x := range tt { |
112 | x := x // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables | |
109 | 113 | b.Run(x.testName, func(b2 *testing.B) { |
110 | 114 | for y := 0; y < b2.N; y++ { |
111 | 115 | _, _ = ParseCommaSeparatedInt(x.stringCodes) |
0 | 0 | package helper |
1 | 1 | |
2 | 2 | import ( |
3 | "math/rand" | |
4 | "time" | |
3 | "crypto/rand" | |
4 | "math/big" | |
5 | 5 | ) |
6 | 6 | |
7 | // molint:gochecknoglobals | |
7 | 8 | var userAgents = [...]string{ |
8 | 9 | "Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0", |
9 | 10 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0", |
4665 | 4666 | } |
4666 | 4667 | |
4667 | 4668 | // GetRandomUserAgent picks a random user agent from a predefined list |
4668 | func GetRandomUserAgent() string { | |
4669 | rand.Seed(time.Now().Unix()) | |
4670 | return userAgents[rand.Intn(len(userAgents))] | |
4669 | func GetRandomUserAgent() (string, error) { | |
4670 | n, err := rand.Int(rand.Reader, big.NewInt(int64(len(userAgents)))) | |
4671 | if err != nil { | |
4672 | return "", err | |
4673 | } | |
4674 | return userAgents[n.Int64()], err | |
4671 | 4675 | } |
1 | 1 | |
2 | 2 | import ( |
3 | 3 | "bytes" |
4 | "errors" | |
4 | 5 | "fmt" |
5 | 6 | "io" |
6 | 7 | "sort" |
115 | 116 | count += bytes.Count(buf[:c], lineSep) |
116 | 117 | |
117 | 118 | switch { |
118 | case err == io.EOF: | |
119 | case errors.Is(err, io.EOF): | |
119 | 120 | return count, nil |
120 | 121 | |
121 | 122 | case err != nil: |
7 | 7 | ) |
8 | 8 | |
9 | 9 | func TestNewStringSet(t *testing.T) { |
10 | t.Parallel() | |
10 | 11 | if NewStringSet().Set == nil { |
11 | 12 | t.Fatal("newStringSet returned nil Set") |
12 | 13 | } |
13 | 14 | } |
14 | 15 | |
15 | 16 | func TestNewIntSet(t *testing.T) { |
17 | t.Parallel() | |
16 | 18 | if NewIntSet().Set == nil { |
17 | 19 | t.Fatal("newIntSet returned nil Set") |
18 | 20 | } |
19 | 21 | } |
20 | 22 | |
21 | 23 | func TestStringSetAdd(t *testing.T) { |
24 | t.Parallel() | |
22 | 25 | x := NewStringSet() |
23 | 26 | x.Add("test") |
24 | 27 | if len(x.Set) != 1 { |
27 | 30 | } |
28 | 31 | |
29 | 32 | func TestStringSetAddDouble(t *testing.T) { |
33 | t.Parallel() | |
30 | 34 | x := NewStringSet() |
31 | 35 | x.Add("test") |
32 | 36 | x.Add("test") |
36 | 40 | } |
37 | 41 | |
38 | 42 | func TestStringSetAddRange(t *testing.T) { |
43 | t.Parallel() | |
39 | 44 | x := NewStringSet() |
40 | 45 | x.AddRange([]string{"string1", "string2"}) |
41 | 46 | if len(x.Set) != 2 { |
44 | 49 | } |
45 | 50 | |
46 | 51 | func TestStringSetAddRangeDouble(t *testing.T) { |
52 | t.Parallel() | |
47 | 53 | x := NewStringSet() |
48 | 54 | x.AddRange([]string{"string1", "string2", "string1", "string2"}) |
49 | 55 | if len(x.Set) != 2 { |
52 | 58 | } |
53 | 59 | |
54 | 60 | func TestStringSetContains(t *testing.T) { |
61 | t.Parallel() | |
55 | 62 | x := NewStringSet() |
56 | 63 | v := []string{"string1", "string2", "1234", "5678"} |
57 | 64 | x.AddRange(v) |
63 | 70 | } |
64 | 71 | |
65 | 72 | func TestStringSetContainsAny(t *testing.T) { |
73 | t.Parallel() | |
66 | 74 | x := NewStringSet() |
67 | 75 | v := []string{"string1", "string2", "1234", "5678"} |
68 | 76 | x.AddRange(v) |
77 | 85 | } |
78 | 86 | |
79 | 87 | func TestStringSetStringify(t *testing.T) { |
88 | t.Parallel() | |
80 | 89 | x := NewStringSet() |
81 | 90 | v := []string{"string1", "string2", "1234", "5678"} |
82 | 91 | x.AddRange(v) |
90 | 99 | } |
91 | 100 | |
92 | 101 | func TestIntSetAdd(t *testing.T) { |
102 | t.Parallel() | |
93 | 103 | x := NewIntSet() |
94 | 104 | x.Add(1) |
95 | 105 | if len(x.Set) != 1 { |
98 | 108 | } |
99 | 109 | |
100 | 110 | func TestIntSetAddDouble(t *testing.T) { |
111 | t.Parallel() | |
101 | 112 | x := NewIntSet() |
102 | 113 | x.Add(1) |
103 | 114 | x.Add(1) |
107 | 118 | } |
108 | 119 | |
109 | 120 | func TestIntSetContains(t *testing.T) { |
121 | t.Parallel() | |
110 | 122 | x := NewIntSet() |
111 | 123 | v := []int{1, 2, 3, 4} |
112 | 124 | for _, y := range v { |
120 | 132 | } |
121 | 133 | |
122 | 134 | func TestIntSetStringify(t *testing.T) { |
135 | t.Parallel() | |
123 | 136 | x := NewIntSet() |
124 | 137 | v := []int{1, 3, 2, 4} |
125 | 138 | expected := "1,2,3,4" |
134 | 147 | } |
135 | 148 | |
136 | 149 | func TestLineCounter(t *testing.T) { |
150 | t.Parallel() | |
137 | 151 | var tt = []struct { |
138 | 152 | testName string |
139 | 153 | s string |
146 | 160 | {"Empty", "", 1}, |
147 | 161 | } |
148 | 162 | for _, x := range tt { |
163 | x := x // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables | |
149 | 164 | t.Run(x.testName, func(t *testing.T) { |
165 | t.Parallel() | |
150 | 166 | r := strings.NewReader(x.s) |
151 | 167 | l, err := lineCounter(r) |
152 | 168 | if err != nil { |
160 | 176 | } |
161 | 177 | |
162 | 178 | func TestLineCounterError(t *testing.T) { |
179 | t.Parallel() | |
163 | 180 | r := iotest.TimeoutReader(strings.NewReader("test")) |
164 | 181 | _, err := lineCounter(r) |
165 | 182 | if !errors.Is(err, iotest.ErrTimeout) { |
5 | 5 | "errors" |
6 | 6 | "fmt" |
7 | 7 | "io" |
8 | "io/ioutil" | |
9 | 8 | "net/http" |
10 | 9 | "net/url" |
11 | 10 | "strings" |
20 | 19 | // HTTPClient represents a http object |
21 | 20 | type HTTPClient struct { |
22 | 21 | client *http.Client |
23 | context context.Context | |
24 | 22 | userAgent string |
25 | 23 | defaultUserAgent string |
26 | 24 | username string |
28 | 26 | headers []HTTPHeader |
29 | 27 | cookies string |
30 | 28 | method string |
29 | host string | |
31 | 30 | } |
32 | 31 | |
33 | 32 | // RequestOptions is used to pass options to a single individual request |
38 | 37 | } |
39 | 38 | |
40 | 39 | // NewHTTPClient returns a new HTTPClient |
41 | func NewHTTPClient(c context.Context, opt *HTTPOptions) (*HTTPClient, error) { | |
40 | func NewHTTPClient(opt *HTTPOptions) (*HTTPClient, error) { | |
42 | 41 | var proxyURLFunc func(*http.Request) (*url.URL, error) |
43 | 42 | var client HTTPClient |
44 | 43 | proxyURLFunc = http.ProxyFromEnvironment |
75 | 74 | InsecureSkipVerify: opt.NoTLSValidation, |
76 | 75 | }, |
77 | 76 | }} |
78 | client.context = c | |
79 | 77 | client.username = opt.Username |
80 | 78 | client.password = opt.Password |
81 | 79 | client.userAgent = opt.UserAgent |
86 | 84 | if client.method == "" { |
87 | 85 | client.method = http.MethodGet |
88 | 86 | } |
87 | // Host header needs to be set separately | |
88 | for _, h := range opt.Headers { | |
89 | if h.Name == "Host" { | |
90 | client.host = h.Value | |
91 | break | |
92 | } | |
93 | } | |
89 | 94 | return &client, nil |
90 | 95 | } |
91 | 96 | |
92 | 97 | // Request makes an http request and returns the status, the content length, the headers, the body and an error |
93 | 98 | // if you want the body returned set the corresponding property inside RequestOptions |
94 | func (client *HTTPClient) Request(fullURL string, opts RequestOptions) (*int, int64, http.Header, []byte, error) { | |
95 | resp, err := client.makeRequest(fullURL, opts.Host, opts.Body) | |
99 | func (client *HTTPClient) Request(ctx context.Context, fullURL string, opts RequestOptions) (*int, int64, http.Header, []byte, error) { | |
100 | resp, err := client.makeRequest(ctx, fullURL, opts.Host, opts.Body) | |
96 | 101 | if err != nil { |
97 | 102 | // ignore context canceled errors |
98 | if errors.Is(client.context.Err(), context.Canceled) { | |
103 | if errors.Is(ctx.Err(), context.Canceled) { | |
99 | 104 | return nil, 0, nil, nil, nil |
100 | 105 | } |
101 | 106 | return nil, 0, nil, nil, err |
105 | 110 | var body []byte |
106 | 111 | var length int64 |
107 | 112 | if opts.ReturnBody { |
108 | body, err = ioutil.ReadAll(resp.Body) | |
113 | body, err = io.ReadAll(resp.Body) | |
109 | 114 | if err != nil { |
110 | 115 | return nil, 0, nil, nil, fmt.Errorf("could not read body %w", err) |
111 | 116 | } |
113 | 118 | } else { |
114 | 119 | // DO NOT REMOVE! |
115 | 120 | // absolutely needed so golang will reuse connections! |
116 | length, err = io.Copy(ioutil.Discard, resp.Body) | |
121 | length, err = io.Copy(io.Discard, resp.Body) | |
117 | 122 | if err != nil { |
118 | 123 | return nil, 0, nil, nil, err |
119 | 124 | } |
122 | 127 | return &resp.StatusCode, length, resp.Header, body, nil |
123 | 128 | } |
124 | 129 | |
125 | func (client *HTTPClient) makeRequest(fullURL, host string, data io.Reader) (*http.Response, error) { | |
130 | func (client *HTTPClient) makeRequest(ctx context.Context, fullURL, host string, data io.Reader) (*http.Response, error) { | |
126 | 131 | req, err := http.NewRequest(client.method, fullURL, data) |
127 | 132 | if err != nil { |
128 | 133 | return nil, err |
129 | 134 | } |
130 | 135 | |
131 | 136 | // add the context so we can easily cancel out |
132 | req = req.WithContext(client.context) | |
137 | req = req.WithContext(ctx) | |
133 | 138 | |
134 | 139 | if client.cookies != "" { |
135 | 140 | req.Header.Set("Cookie", client.cookies) |
136 | 141 | } |
137 | 142 | |
143 | // Use host for VHOST mode on a per request basis, otherwise the one provided from headers | |
138 | 144 | if host != "" { |
139 | 145 | req.Host = host |
146 | } else if client.host != "" { | |
147 | req.Host = client.host | |
140 | 148 | } |
141 | 149 | |
142 | 150 | if client.userAgent != "" { |
156 | 164 | |
157 | 165 | resp, err := client.client.Do(req) |
158 | 166 | if err != nil { |
159 | if ue, ok := err.(*url.Error); ok { | |
167 | var ue *url.Error | |
168 | if errors.As(err, &ue) { | |
160 | 169 | if strings.HasPrefix(ue.Err.Error(), "x509") { |
161 | 170 | return nil, fmt.Errorf("invalid certificate: %w", ue.Err) |
162 | 171 | } |
2 | 2 | import ( |
3 | 3 | "bytes" |
4 | 4 | "context" |
5 | "crypto/rand" | |
5 | 6 | "fmt" |
6 | "math/rand" | |
7 | "math/big" | |
7 | 8 | "net/http" |
8 | 9 | "net/http/httptest" |
9 | 10 | "testing" |
25 | 26 | return ts |
26 | 27 | } |
27 | 28 | |
28 | func randomString(length int) string { | |
29 | func randomString(length int) (string, error) { | |
29 | 30 | var letter = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") |
30 | 31 | letterLen := len(letter) |
31 | 32 | |
32 | 33 | b := make([]byte, length) |
33 | 34 | for i := range b { |
34 | b[i] = letter[rand.Intn(letterLen)] | |
35 | n, err := rand.Int(rand.Reader, big.NewInt(int64(letterLen))) | |
36 | if err != nil { | |
37 | return "", err | |
38 | } | |
39 | b[i] = letter[n.Int64()] | |
35 | 40 | } |
36 | return string(b) | |
41 | return string(b), nil | |
37 | 42 | } |
38 | 43 | |
39 | 44 | func TestRequest(t *testing.T) { |
40 | ret := randomString(100) | |
45 | t.Parallel() | |
46 | ret, err := randomString(100) | |
47 | if err != nil { | |
48 | t.Fatal(err) | |
49 | } | |
41 | 50 | h := httpServerT(t, ret) |
42 | 51 | defer h.Close() |
43 | 52 | var o HTTPOptions |
44 | c, err := NewHTTPClient(context.Background(), &o) | |
53 | c, err := NewHTTPClient(&o) | |
45 | 54 | if err != nil { |
46 | 55 | t.Fatalf("Got Error: %v", err) |
47 | 56 | } |
48 | status, length, _, body, err := c.Request(h.URL, RequestOptions{ReturnBody: true}) | |
57 | status, length, _, body, err := c.Request(context.Background(), h.URL, RequestOptions{ReturnBody: true}) | |
49 | 58 | if err != nil { |
50 | 59 | t.Fatalf("Got Error: %v", err) |
51 | 60 | } |
61 | 70 | } |
62 | 71 | |
63 | 72 | func BenchmarkRequestWithoutBody(b *testing.B) { |
64 | h := httpServerB(b, randomString(10000)) | |
73 | r, err := randomString(10000) | |
74 | if err != nil { | |
75 | b.Fatal(err) | |
76 | } | |
77 | h := httpServerB(b, r) | |
65 | 78 | defer h.Close() |
66 | 79 | var o HTTPOptions |
67 | c, err := NewHTTPClient(context.Background(), &o) | |
80 | c, err := NewHTTPClient(&o) | |
68 | 81 | if err != nil { |
69 | 82 | b.Fatalf("Got Error: %v", err) |
70 | 83 | } |
71 | 84 | for x := 0; x < b.N; x++ { |
72 | _, _, _, _, err := c.Request(h.URL, RequestOptions{ReturnBody: false}) | |
85 | _, _, _, _, err := c.Request(context.Background(), h.URL, RequestOptions{ReturnBody: false}) | |
73 | 86 | if err != nil { |
74 | 87 | b.Fatalf("Got Error: %v", err) |
75 | 88 | } |
77 | 90 | } |
78 | 91 | |
79 | 92 | func BenchmarkRequestWitBody(b *testing.B) { |
80 | h := httpServerB(b, randomString(10000)) | |
93 | r, err := randomString(10000) | |
94 | if err != nil { | |
95 | b.Fatal(err) | |
96 | } | |
97 | h := httpServerB(b, r) | |
81 | 98 | defer h.Close() |
82 | 99 | var o HTTPOptions |
83 | c, err := NewHTTPClient(context.Background(), &o) | |
100 | c, err := NewHTTPClient(&o) | |
84 | 101 | if err != nil { |
85 | 102 | b.Fatalf("Got Error: %v", err) |
86 | 103 | } |
87 | 104 | for x := 0; x < b.N; x++ { |
88 | _, _, _, _, err := c.Request(h.URL, RequestOptions{ReturnBody: true}) | |
105 | _, _, _, _, err := c.Request(context.Background(), h.URL, RequestOptions{ReturnBody: true}) | |
89 | 106 | if err != nil { |
90 | 107 | b.Fatalf("Got Error: %v", err) |
91 | 108 | } |
93 | 110 | } |
94 | 111 | |
95 | 112 | func BenchmarkNewHTTPClient(b *testing.B) { |
96 | h := httpServerB(b, randomString(500)) | |
113 | r, err := randomString(500) | |
114 | if err != nil { | |
115 | b.Fatal(err) | |
116 | } | |
117 | h := httpServerB(b, r) | |
97 | 118 | defer h.Close() |
98 | 119 | var o HTTPOptions |
99 | 120 | for x := 0; x < b.N; x++ { |
100 | _, err := NewHTTPClient(context.Background(), &o) | |
121 | _, err := NewHTTPClient(&o) | |
101 | 122 | if err != nil { |
102 | 123 | b.Fatalf("Got Error: %v", err) |
103 | 124 | } |
0 | 0 | package libgobuster |
1 | ||
2 | import "context" | |
1 | 3 | |
2 | 4 | // GobusterPlugin is an interface which plugins must implement |
3 | 5 | type GobusterPlugin interface { |
4 | 6 | Name() string |
5 | 7 | RequestsPerRun() int |
6 | PreRun() error | |
7 | Run(string, chan<- Result) error | |
8 | PreRun(context.Context) error | |
9 | Run(context.Context, string, chan<- Result) error | |
8 | 10 | GetConfigString() (string, error) |
9 | 11 | } |
10 | 12 | |
13 | // Result is an interface for the Result object | |
11 | 14 | type Result interface { |
12 | 15 | ResultToString() (string, error) |
13 | 16 | } |
25 | 25 | // Gobuster is the main object when creating a new run |
26 | 26 | type Gobuster struct { |
27 | 27 | Opts *Options |
28 | context context.Context | |
29 | 28 | RequestsExpected int |
30 | 29 | RequestsIssued int |
31 | 30 | RequestsCountMutex *sync.RWMutex |
37 | 36 | } |
38 | 37 | |
39 | 38 | // NewGobuster returns a new Gobuster object |
40 | func NewGobuster(c context.Context, opts *Options, plugin GobusterPlugin) (*Gobuster, error) { | |
39 | func NewGobuster(opts *Options, plugin GobusterPlugin) (*Gobuster, error) { | |
41 | 40 | var g Gobuster |
42 | 41 | g.Opts = opts |
43 | 42 | g.plugin = plugin |
44 | 43 | g.RequestsCountMutex = new(sync.RWMutex) |
45 | g.context = c | |
46 | 44 | g.resultChan = make(chan Result) |
47 | 45 | g.errorChan = make(chan error) |
48 | 46 | g.LogInfo = log.New(os.Stdout, "", log.LstdFlags) |
67 | 65 | g.RequestsCountMutex.Unlock() |
68 | 66 | } |
69 | 67 | |
70 | func (g *Gobuster) worker(wordChan <-chan string, wg *sync.WaitGroup) { | |
68 | func (g *Gobuster) worker(ctx context.Context, wordChan <-chan string, wg *sync.WaitGroup) { | |
71 | 69 | defer wg.Done() |
72 | 70 | for { |
73 | 71 | select { |
74 | case <-g.context.Done(): | |
72 | case <-ctx.Done(): | |
75 | 73 | return |
76 | 74 | case word, ok := <-wordChan: |
77 | 75 | // worker finished |
87 | 85 | } |
88 | 86 | |
89 | 87 | // Mode-specific processing |
90 | err := g.plugin.Run(wordCleaned, g.resultChan) | |
88 | err := g.plugin.Run(ctx, wordCleaned, g.resultChan) | |
91 | 89 | if err != nil { |
92 | 90 | // do not exit and continue |
93 | 91 | g.errorChan <- err |
95 | 93 | } |
96 | 94 | |
97 | 95 | select { |
98 | case <-g.context.Done(): | |
96 | case <-ctx.Done(): | |
99 | 97 | case <-time.After(g.Opts.Delay): |
100 | 98 | } |
101 | 99 | } |
136 | 134 | return bufio.NewScanner(wordlist), nil |
137 | 135 | } |
138 | 136 | |
139 | // Start the busting of the website with the given | |
137 | // Run the busting of the website with the given | |
140 | 138 | // set of settings from the command line. |
141 | func (g *Gobuster) Start() error { | |
139 | func (g *Gobuster) Run(ctx context.Context) error { | |
142 | 140 | defer close(g.resultChan) |
143 | 141 | defer close(g.errorChan) |
144 | 142 | |
145 | if err := g.plugin.PreRun(); err != nil { | |
143 | if err := g.plugin.PreRun(ctx); err != nil { | |
146 | 144 | return err |
147 | 145 | } |
148 | 146 | |
154 | 152 | // Create goroutines for each of the number of threads |
155 | 153 | // specified. |
156 | 154 | for i := 0; i < g.Opts.Threads; i++ { |
157 | go g.worker(wordChan, &workerGroup) | |
155 | go g.worker(ctx, wordChan, &workerGroup) | |
158 | 156 | } |
159 | 157 | |
160 | 158 | scanner, err := g.getWordlist() |
165 | 163 | Scan: |
166 | 164 | for scanner.Scan() { |
167 | 165 | select { |
168 | case <-g.context.Done(): | |
166 | case <-ctx.Done(): | |
169 | 167 | break Scan |
170 | 168 | default: |
171 | 169 | word := scanner.Text() |
176 | 174 | for _, w := range perms { |
177 | 175 | select { |
178 | 176 | // need to check here too otherwise wordChan will block |
179 | case <-g.context.Done(): | |
177 | case <-ctx.Done(): | |
180 | 178 | break Scan |
181 | 179 | case wordChan <- w: |
182 | 180 | } |
12 | 12 | NoProgress bool |
13 | 13 | NoError bool |
14 | 14 | Quiet bool |
15 | WildcardForced bool | |
16 | 15 | Verbose bool |
17 | 16 | Delay time.Duration |
18 | 17 | } |
5 | 5 | |
6 | 6 | // BasicHTTPOptions defines only core http options |
7 | 7 | type BasicHTTPOptions struct { |
8 | UserAgent string | |
9 | Proxy string | |
10 | Timeout time.Duration | |
8 | UserAgent string | |
9 | Proxy string | |
10 | NoTLSValidation bool | |
11 | Timeout time.Duration | |
11 | 12 | } |
12 | 13 | |
13 | 14 | // HTTPOptions is the struct to pass in all http options to Gobuster |
14 | 15 | type HTTPOptions struct { |
15 | 16 | BasicHTTPOptions |
16 | Password string | |
17 | URL string | |
18 | Username string | |
19 | Cookies string | |
20 | Headers []HTTPHeader | |
21 | FollowRedirect bool | |
22 | NoTLSValidation bool | |
23 | Method string | |
17 | Password string | |
18 | URL string | |
19 | Username string | |
20 | Cookies string | |
21 | Headers []HTTPHeader | |
22 | FollowRedirect bool | |
23 | Method string | |
24 | 24 | } |