diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f761aca0..06c6601a 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: ["1.14.13", "1.15.6"] + go: ["1.16.0"] steps: - name: Set up Go ${{ matrix.go }} uses: actions/setup-go@v2 diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index 20ef06ee..00000000 --- a/.golangci.yml +++ /dev/null @@ -1,51 +0,0 @@ -linters: - enable-all: true - disable: - - wsl - - gocyclo - - gocognit - - funlen - - lll - - dogsled - - gomnd - - nestif - - testpackage - - godot - - goerr113 - - gofumpt - - exhaustivestruct - - forbidigo - - nlreturn - - wrapcheck - -issues: - exclude-rules: - - text: "TLS InsecureSkipVerify may be true" - linters: - - gosec - - - text: ifElseChain - linters: - - gocritic - - - text: exitAfterDefer - linters: - - gocritic - - - path: cli\\cmd\\.+\.go - linters: - - gochecknoinits - - gochecknoglobals - - - path: cli/cmd/.+\.go - linters: - - gochecknoinits - - gochecknoglobals - - - path: helper/useragents.go - linters: - - gochecknoglobals - - - path: _test\.go - linters: - - scopelint diff --git a/Dockerfile b/Dockerfile index 67b08ff0..104a2796 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ FROM golang:latest AS build-env WORKDIR /src -ENV GO111MODULE=on +ENV CGO_ENABLED=0 COPY go.mod /src/ RUN go mod download COPY . . -RUN CGO_ENABLED=0 GOOS=linux go build -a -o gobuster -ldflags="-s -w" -gcflags="all=-trimpath=/src" -asmflags="all=-trimpath=/src" +RUN go build -a -o gobuster -ldflags="-s -w" -gcflags="all=-trimpath=/src" -asmflags="all=-trimpath=/src" FROM alpine:latest diff --git a/Makefile b/Makefile index 1f094008..bdbe480b 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,23 @@ TARGET=./build ARCHS=amd64 386 LDFLAGS="-s -w" +.PHONY: current current: @go build -o ./gobuster; \ echo "Done." +.PHONY: fmt fmt: @go fmt ./...; \ echo "Done." +.PHONY: update update: @go get -u; \ go mod tidy -v; \ echo "Done." +.PHONY: windows windows: @for GOARCH in ${ARCHS}; do \ echo "Building for windows $${GOARCH} ..." ; \ @@ -23,6 +27,7 @@ windows: done; \ echo "Done." +.PHONY: linux linux: @for GOARCH in ${ARCHS}; do \ echo "Building for linux $${GOARCH} ..." ; \ @@ -31,6 +36,7 @@ linux: done; \ echo "Done." +.PHONY: darwin darwin: @for GOARCH in ${ARCHS}; do \ echo "Building for darwin $${GOARCH} ..." ; \ @@ -39,19 +45,30 @@ darwin: done; \ echo "Done." +.PHONY: all all: clean fmt update test lint darwin linux windows +.PHONY: test test: @go test -v -race ./... ; \ echo "Done." +.PHONY: lint lint: - @if [ ! -f "$$(go env GOPATH)/bin/golangci-lint" ]; then \ - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin; \ - fi "$$(go env GOPATH)/bin/golangci-lint" run ./... go mod tidy +.PHONY: lint-update +lint-update: + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin + $$(go env GOPATH)/bin/golangci-lint --version + +.PHONY: lint-docker +lint-docker: + docker pull golangci/golangci-lint:latest + docker run --rm -v $$(pwd):/app -w /app golangci/golangci-lint:latest golangci-lint run + +.PHONY: clean clean: @rm -rf ${TARGET}/* ; \ go clean ./... ; \ diff --git a/README.md b/README.md index d008399a..9bd1a110 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Gobuster is a tool used to brute-force: -* URIs (directories and files) in web sites. -* DNS subdomains (with wildcard support). -* Virtual Host names on target web servers. -* Open Amazon S3 buckets +- URIs (directories and files) in web sites. +- DNS subdomains (with wildcard support). +- Virtual Host names on target web servers. +- Open Amazon S3 buckets ## Tags, Statuses, etc @@ -29,8 +29,8 @@ Because I wanted: Yes, you're probably correct. Feel free to: -* Not use it. -* Show me how to do it better. +- Not use it. +- Show me how to do it better. ## Love this tool? Back it! @@ -40,34 +40,39 @@ If you're backing us already, you rock. If you're not, that's cool too! Want to 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. +## Changes in 3.1-dev + +- Use go 1.16 +- use contexts in the correct way + ## Changes in 3.1 -* enumerate public AWS S3 buckets -* fuzzing mode -* specify HTTP method -* 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. -* The shorthand `p` flag which was assigned to proxy is now used by the pattern flag +- enumerate public AWS S3 buckets +- fuzzing mode +- specify HTTP method +- 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. +- The shorthand `p` flag which was assigned to proxy is now used by the pattern flag ## Changes in 3.0 -* New CLI options so modes are strictly separated (`-m` is now gone!) -* Performance Optimizations and better connection handling -* Ability to enumerate vhost names -* Option to supply custom HTTP headers +- New CLI options so modes are strictly separated (`-m` is now gone!) +- Performance Optimizations and better connection handling +- Ability to enumerate vhost names +- Option to supply custom HTTP headers ## Available Modes -* dir - the classic directory brute-forcing mode -* dns - DNS subdomain brute-forcing mode -* s3 - Enumerate open S3 buckets and look for existence and bucket listings -* vhost - virtual host brute-forcing mode (not the same as DNS!) +- dir - the classic directory brute-forcing mode +- dns - DNS subdomain brute-forcing mode +- s3 - Enumerate open S3 buckets and look for existence and bucket listings +- vhost - virtual host brute-forcing mode (not the same as DNS!) ## Built-in Help Help is built-in! -* `gobuster help` - outputs the top-level help. -* `gobuster help ` - outputs the help specific to that mode. +- `gobuster help` - outputs the top-level help. +- `gobuster help ` - outputs the help specific to that mode. ## `dns` Mode Help @@ -177,9 +182,11 @@ If you have a [Go](https://golang.org/) environment ready to go, it's as easy as go get github.com/OJ/gobuster ``` +PS: You need at least go 1.16.0 to compile gobuster. + ## Building From Source -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. +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.16.0 to compile gobuster. ### Compiling @@ -197,13 +204,13 @@ go install If you have all the dependencies already, you can make use of the build scripts: -* `make` - builds for the current Go configuration (ie. runs `go build`). -* `make windows` - builds 32 and 64 bit binaries for windows, and writes them to the `build` folder. -* `make linux` - builds 32 and 64 bit binaries for linux, and writes them to the `build` folder. -* `make darwin` - builds 32 and 64 bit binaries for darwin, and writes them to the `build` folder. -* `make all` - builds for all platforms and architectures, and writes the resulting binaries to the `build` folder. -* `make clean` - clears out the `build` folder. -* `make test` - runs the tests. +- `make` - builds for the current Go configuration (ie. runs `go build`). +- `make windows` - builds 32 and 64 bit binaries for windows, and writes them to the `build` folder. +- `make linux` - builds 32 and 64 bit binaries for linux, and writes them to the `build` folder. +- `make darwin` - builds 32 and 64 bit binaries for darwin, and writes them to the `build` folder. +- `make all` - builds for all platforms and architectures, and writes the resulting binaries to the `build` folder. +- `make clean` - clears out the `build` folder. +- `make test` - runs the tests. ## Wordlists via STDIN @@ -577,14 +584,14 @@ gobuster fuzz -u https://example.com?FUZZ=test -w parameter-names.txt #### Use case in combination with patterns -* Create a custom wordlist for the target containing company names and so on -* Create a pattern file to use for common bucket names. +- Create a custom wordlist for the target containing company names and so on +- Create a pattern file to use for common bucket names. ```bash curl -s --output - https://raw.githubusercontent.com/eth0izzle/bucket-stream/master/permutations/extended.txt | sed -s 's/%s/{GOBUSTER}/' > patterns.txt ``` -* Run gobuster with the custom input. Be sure to turn verbose mode on to see the bucket details +- Run gobuster with the custom input. Be sure to turn verbose mode on to see the bucket details ```bash gobuster s3 --wordlist my.custom.wordlist -p patterns.txt -v diff --git a/cli/cmd/dir.go b/cli/cmd/dir.go index df6a4e3c..1305fdf7 100644 --- a/cli/cmd/dir.go +++ b/cli/cmd/dir.go @@ -12,6 +12,7 @@ import ( "github.com/spf13/cobra" ) +// nolint:gochecknoglobals var cmdDir *cobra.Command func runDir(cmd *cobra.Command, args []string) error { @@ -20,7 +21,7 @@ func runDir(cmd *cobra.Command, args []string) error { return fmt.Errorf("error on parsing arguments: %w", err) } - plugin, err := gobusterdir.NewGobusterDir(mainContext, globalopts, pluginopts) + plugin, err := gobusterdir.NewGobusterDir(globalopts, pluginopts) if err != nil { return fmt.Errorf("error on creating gobusterdir: %w", err) } @@ -135,6 +136,7 @@ func parseDirOptions() (*libgobuster.Options, *gobusterdir.OptionsDir, error) { return globalopts, plugin, nil } +// nolint:gochecknoinits func init() { cmdDir = &cobra.Command{ Use: "dir", diff --git a/cli/cmd/dir_test.go b/cli/cmd/dir_test.go index ec3b13ae..4e626d3f 100644 --- a/cli/cmd/dir_test.go +++ b/cli/cmd/dir_test.go @@ -3,7 +3,7 @@ package cmd import ( "context" "fmt" - "io/ioutil" + "io" "log" "net/http" "net/http/httptest" @@ -47,7 +47,7 @@ func BenchmarkDirMode(b *testing.B) { } pluginopts.StatusCodesParsed = tmpStat - wordlist, err := ioutil.TempFile("", "") + wordlist, err := os.CreateTemp("", "") if err != nil { b.Fatalf("could not create tempfile: %v", err) } @@ -73,13 +73,13 @@ func BenchmarkDirMode(b *testing.B) { } defer devnull.Close() log.SetFlags(0) - log.SetOutput(ioutil.Discard) + log.SetOutput(io.Discard) // Run the real benchmark for x := 0; x < b.N; x++ { os.Stdout = devnull os.Stderr = devnull - plugin, err := gobusterdir.NewGobusterDir(ctx, &globalopts, pluginopts) + plugin, err := gobusterdir.NewGobusterDir(&globalopts, pluginopts) if err != nil { b.Fatalf("error on creating gobusterdir: %v", err) } diff --git a/cli/cmd/dns.go b/cli/cmd/dns.go index 912d0157..c0810ad4 100644 --- a/cli/cmd/dns.go +++ b/cli/cmd/dns.go @@ -13,6 +13,7 @@ import ( "github.com/spf13/cobra" ) +// nolint:gochecknoglobals var cmdDNS *cobra.Command func runDNS(cmd *cobra.Command, args []string) error { @@ -80,6 +81,7 @@ func parseDNSOptions() (*libgobuster.Options, *gobusterdns.OptionsDNS, error) { return globalopts, plugin, nil } +// nolint:gochecknoinits func init() { cmdDNS = &cobra.Command{ Use: "dns", diff --git a/cli/cmd/fuzz.go b/cli/cmd/fuzz.go index 64c43b96..1f5bf0e3 100644 --- a/cli/cmd/fuzz.go +++ b/cli/cmd/fuzz.go @@ -12,6 +12,7 @@ import ( "github.com/spf13/cobra" ) +// nolint:gochecknoglobals var cmdFuzz *cobra.Command func runFuzz(cmd *cobra.Command, args []string) error { @@ -20,7 +21,7 @@ func runFuzz(cmd *cobra.Command, args []string) error { return fmt.Errorf("error on parsing arguments: %w", err) } - plugin, err := gobusterfuzz.NewGobusterFuzz(mainContext, globalopts, pluginopts) + plugin, err := gobusterfuzz.NewGobusterFuzz(globalopts, pluginopts) if err != nil { return fmt.Errorf("error on creating gobusterfuzz: %w", err) } @@ -86,6 +87,7 @@ func parseFuzzOptions() (*libgobuster.Options, *gobusterfuzz.OptionsFuzz, error) return globalopts, plugin, nil } +// nolint:gochecknoinits func init() { cmdFuzz = &cobra.Command{ Use: "fuzz", diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 4d90aed7..6d2e5347 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -12,11 +12,13 @@ import ( "github.com/spf13/cobra" ) +// nolint:gochecknoglobals var rootCmd = &cobra.Command{ Use: "gobuster", SilenceUsage: true, } +// nolint:gochecknoglobals var mainContext context.Context // Execute is the main cobra method @@ -147,6 +149,7 @@ func configureGlobalOptions() { } } +// nolint:gochecknoinits func init() { rootCmd.PersistentFlags().DurationP("delay", "", 0, "Time each thread waits between requests (e.g. 1500ms)") rootCmd.PersistentFlags().IntP("threads", "t", 10, "Number of concurrent threads") diff --git a/cli/cmd/s3.go b/cli/cmd/s3.go index fc4f8cdf..5e75e1a8 100644 --- a/cli/cmd/s3.go +++ b/cli/cmd/s3.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" ) +// nolint:gochecknoglobals var cmdS3 *cobra.Command func runS3(cmd *cobra.Command, args []string) error { @@ -17,7 +18,7 @@ func runS3(cmd *cobra.Command, args []string) error { return fmt.Errorf("error on parsing arguments: %w", err) } - plugin, err := gobusters3.NewGobusterS3(mainContext, globalopts, pluginopts) + plugin, err := gobusters3.NewGobusterS3(globalopts, pluginopts) if err != nil { return fmt.Errorf("error on creating gobusters3: %w", err) } @@ -54,6 +55,7 @@ func parseS3Options() (*libgobuster.Options, *gobusters3.OptionsS3, error) { return globalopts, plugin, nil } +// nolint:gochecknoinits func init() { cmdS3 = &cobra.Command{ Use: "s3", diff --git a/cli/cmd/version.go b/cli/cmd/version.go index ca1e117e..4a63d50d 100644 --- a/cli/cmd/version.go +++ b/cli/cmd/version.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" ) +// nolint:gochecknoglobals var cmdVersion *cobra.Command func runVersion(cmd *cobra.Command, args []string) error { @@ -14,6 +15,7 @@ func runVersion(cmd *cobra.Command, args []string) error { return nil } +// nolint:gochecknoinits func init() { cmdVersion = &cobra.Command{ Use: "version", diff --git a/cli/cmd/vhost.go b/cli/cmd/vhost.go index 8fc27030..00de78fa 100644 --- a/cli/cmd/vhost.go +++ b/cli/cmd/vhost.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/cobra" ) +// nolint:gochecknoglobals var cmdVhost *cobra.Command func runVhost(cmd *cobra.Command, args []string) error { @@ -18,7 +19,7 @@ func runVhost(cmd *cobra.Command, args []string) error { return fmt.Errorf("error on parsing arguments: %w", err) } - plugin, err := gobustervhost.NewGobusterVhost(mainContext, globalopts, pluginopts) + plugin, err := gobustervhost.NewGobusterVhost(globalopts, pluginopts) if err != nil { return fmt.Errorf("error on creating gobustervhost: %w", err) } @@ -60,6 +61,7 @@ func parseVhostOptions() (*libgobuster.Options, *gobustervhost.OptionsVhost, err return globalopts, &plugin, nil } +// nolint:gochecknoinits func init() { cmdVhost = &cobra.Command{ Use: "vhost", diff --git a/cli/cmd/vhost_test.go b/cli/cmd/vhost_test.go index 624ea8f4..92fc5a2c 100644 --- a/cli/cmd/vhost_test.go +++ b/cli/cmd/vhost_test.go @@ -3,7 +3,7 @@ package cmd import ( "context" "fmt" - "io/ioutil" + "io" "log" "os" "testing" @@ -22,7 +22,7 @@ func BenchmarkVhostMode(b *testing.B) { pluginopts.URL = h.URL pluginopts.Timeout = 10 * time.Second - wordlist, err := ioutil.TempFile("", "") + wordlist, err := os.CreateTemp("", "") if err != nil { b.Fatalf("could not create tempfile: %v", err) } @@ -48,13 +48,13 @@ func BenchmarkVhostMode(b *testing.B) { } defer devnull.Close() log.SetFlags(0) - log.SetOutput(ioutil.Discard) + log.SetOutput(io.Discard) // Run the real benchmark for x := 0; x < b.N; x++ { os.Stdout = devnull os.Stderr = devnull - plugin, err := gobustervhost.NewGobusterVhost(ctx, &globalopts, &pluginopts) + plugin, err := gobustervhost.NewGobusterVhost(&globalopts, &pluginopts) if err != nil { b.Fatalf("error on creating gobusterdir: %v", err) } diff --git a/cli/gobuster.go b/cli/gobuster.go index 36f9e72f..8bb509be 100644 --- a/cli/gobuster.go +++ b/cli/gobuster.go @@ -92,7 +92,7 @@ func errorWorker(g *libgobuster.Gobuster, wg *sync.WaitGroup, output *outputType // progressWorker outputs the progress every tick. It will stop once cancel() is called // on the context -func progressWorker(c context.Context, g *libgobuster.Gobuster, wg *sync.WaitGroup, output *outputType) { +func progressWorker(ctx context.Context, g *libgobuster.Gobuster, wg *sync.WaitGroup, output *outputType) { defer wg.Done() tick := time.NewTicker(cliProgressUpdate) @@ -121,7 +121,7 @@ func progressWorker(c context.Context, g *libgobuster.Gobuster, wg *sync.WaitGro output.Mu.Unlock() g.RequestsCountMutex.RUnlock() } - case <-c.Done(): + case <-ctx.Done(): return } } @@ -136,7 +136,7 @@ func writeToFile(f *os.File, output string) error { } // Gobuster is the main entry point for the CLI -func Gobuster(prevCtx context.Context, opts *libgobuster.Options, plugin libgobuster.GobusterPlugin) error { +func Gobuster(ctx context.Context, opts *libgobuster.Options, plugin libgobuster.GobusterPlugin) error { // Sanity checks if opts == nil { return fmt.Errorf("please provide valid options") @@ -146,10 +146,10 @@ func Gobuster(prevCtx context.Context, opts *libgobuster.Options, plugin libgobu return fmt.Errorf("please provide a valid plugin") } - ctx, cancel := context.WithCancel(prevCtx) + ctxCancel, cancel := context.WithCancel(ctx) defer cancel() - gobuster, err := libgobuster.NewGobuster(ctx, opts, plugin) + gobuster, err := libgobuster.NewGobuster(opts, plugin) if err != nil { return err } @@ -188,10 +188,10 @@ func Gobuster(prevCtx context.Context, opts *libgobuster.Options, plugin libgobu if !opts.Quiet && !opts.NoProgress { // if not quiet add a new workgroup entry and start the goroutine wg.Add(1) - go progressWorker(ctx, gobuster, &wg, o) + go progressWorker(ctxCancel, gobuster, &wg, o) } - err = gobuster.Start() + err = gobuster.Run(ctxCancel) // call cancel func so progressWorker will exit (the only goroutine in this // file using the context) and to free resources diff --git a/go.mod b/go.mod index 3d1291a6..64f1df06 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,9 @@ module github.com/OJ/gobuster/v3 require ( github.com/google/uuid v1.2.0 - github.com/spf13/cobra v1.1.1 - golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect - golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf + github.com/spf13/cobra v1.1.3 + golang.org/x/sys v0.0.0-20210223212115-eede4237b368 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d ) -go 1.15 +go 1.16 diff --git a/go.sum b/go.sum index 02151f67..8c86b3c7 100644 --- a/go.sum +++ b/go.sum @@ -32,7 +32,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -126,7 +125,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -151,17 +149,15 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -205,7 +201,6 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -233,11 +228,10 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20210223212115-eede4237b368 h1:fDE3p0qf2V1co1vfj3/o87Ps8Hq6QTGNxJ5Xe7xSp80= +golang.org/x/sys v0.0.0-20210223212115-eede4237b368/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -291,7 +285,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/gobusterdir/gobusterdir.go b/gobusterdir/gobusterdir.go index 49277111..bedbaa42 100644 --- a/gobusterdir/gobusterdir.go +++ b/gobusterdir/gobusterdir.go @@ -40,7 +40,7 @@ type GobusterDir struct { } // NewGobusterDir creates a new initialized GobusterDir -func NewGobusterDir(cont context.Context, globalopts *libgobuster.Options, opts *OptionsDir) (*GobusterDir, error) { +func NewGobusterDir(globalopts *libgobuster.Options, opts *OptionsDir) (*GobusterDir, error) { if globalopts == nil { return nil, fmt.Errorf("please provide valid global options") } @@ -71,7 +71,7 @@ func NewGobusterDir(cont context.Context, globalopts *libgobuster.Options, opts Method: opts.Method, } - h, err := libgobuster.NewHTTPClient(cont, &httpOpts) + h, err := libgobuster.NewHTTPClient(&httpOpts) if err != nil { return nil, err } @@ -106,13 +106,13 @@ func (d *GobusterDir) RequestsPerRun() int { } // PreRun is the pre run implementation of gobusterdir -func (d *GobusterDir) PreRun() error { +func (d *GobusterDir) PreRun(ctx context.Context) error { // add trailing slash if !strings.HasSuffix(d.options.URL, "/") { d.options.URL = fmt.Sprintf("%s/", d.options.URL) } - _, _, _, _, err := d.http.Request(d.options.URL, libgobuster.RequestOptions{}) + _, _, _, _, err := d.http.Request(ctx, d.options.URL, libgobuster.RequestOptions{}) if err != nil { return fmt.Errorf("unable to connect to %s: %w", d.options.URL, err) } @@ -123,7 +123,7 @@ func (d *GobusterDir) PreRun() error { url = fmt.Sprintf("%s/", url) } - wildcardResp, wildcardLength, _, _, err := d.http.Request(url, libgobuster.RequestOptions{}) + wildcardResp, wildcardLength, _, _, err := d.http.Request(ctx, url, libgobuster.RequestOptions{}) if err != nil { return err } @@ -164,7 +164,7 @@ func getBackupFilenames(word string) []string { } // Run is the process implementation of gobusterdir -func (d *GobusterDir) Run(word string, resChannel chan<- libgobuster.Result) error { +func (d *GobusterDir) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { suffix := "" if d.options.UseSlash { suffix = "/" @@ -197,7 +197,7 @@ func (d *GobusterDir) Run(word string, resChannel chan<- libgobuster.Result) err } for entity, url := range urlsToCheck { - statusCode, size, header, _, err := d.http.Request(url, libgobuster.RequestOptions{}) + statusCode, size, header, _, err := d.http.Request(ctx, url, libgobuster.RequestOptions{}) if err != nil { return err } diff --git a/gobusterdns/gobusterdns.go b/gobusterdns/gobusterdns.go index e2efb33f..b883fc1d 100644 --- a/gobusterdns/gobusterdns.go +++ b/gobusterdns/gobusterdns.go @@ -82,10 +82,10 @@ func (d *GobusterDNS) RequestsPerRun() int { } // PreRun is the pre run implementation of gobusterdns -func (d *GobusterDNS) PreRun() error { +func (d *GobusterDNS) PreRun(ctx context.Context) error { // Resolve a subdomain that probably shouldn't exist guid := uuid.New() - wildcardIps, err := d.dnsLookup(fmt.Sprintf("%s.%s", guid, d.options.Domain)) + wildcardIps, err := d.dnsLookup(ctx, fmt.Sprintf("%s.%s", guid, d.options.Domain)) if err == nil { d.isWildcard = true d.wildcardIps.AddRange(wildcardIps) @@ -96,7 +96,7 @@ func (d *GobusterDNS) PreRun() error { if !d.globalopts.Quiet { // Provide a warning if the base domain doesn't resolve (in case of typo) - _, err = d.dnsLookup(d.options.Domain) + _, err = d.dnsLookup(ctx, d.options.Domain) if err != nil { // Not an error, just a warning. Eg. `yp.to` doesn't resolve, but `cr.yp.to` does! log.Printf("[-] Unable to validate base domain: %s (%v)", d.options.Domain, err) @@ -107,9 +107,9 @@ func (d *GobusterDNS) PreRun() error { } // Run is the process implementation of gobusterdns -func (d *GobusterDNS) Run(word string, resChannel chan<- libgobuster.Result) error { +func (d *GobusterDNS) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { subdomain := fmt.Sprintf("%s.%s", word, d.options.Domain) - ips, err := d.dnsLookup(subdomain) + ips, err := d.dnsLookup(ctx, subdomain) if err == nil { if !d.isWildcard || !d.wildcardIps.ContainsAny(ips) { result := Result{ @@ -121,7 +121,7 @@ func (d *GobusterDNS) Run(word string, resChannel chan<- libgobuster.Result) err if d.options.ShowIPs { result.IPs = ips } else if d.options.ShowCNAME { - cname, err := d.dnsLookupCname(subdomain) + cname, err := d.dnsLookupCname(ctx, subdomain) if err == nil { result.CNAME = cname } @@ -219,15 +219,15 @@ func (d *GobusterDNS) GetConfigString() (string, error) { return strings.TrimSpace(buffer.String()), nil } -func (d *GobusterDNS) dnsLookup(domain string) ([]string, error) { - ctx, cancel := context.WithTimeout(context.Background(), d.options.Timeout) +func (d *GobusterDNS) dnsLookup(ctx context.Context, domain string) ([]string, error) { + ctx2, cancel := context.WithTimeout(ctx, d.options.Timeout) defer cancel() - return d.resolver.LookupHost(ctx, domain) + return d.resolver.LookupHost(ctx2, domain) } -func (d *GobusterDNS) dnsLookupCname(domain string) (string, error) { - ctx, cancel := context.WithTimeout(context.Background(), d.options.Timeout) +func (d *GobusterDNS) dnsLookupCname(ctx context.Context, domain string) (string, error) { + ctx2, cancel := context.WithTimeout(ctx, d.options.Timeout) defer cancel() time.Sleep(time.Second) - return d.resolver.LookupCNAME(ctx, domain) + return d.resolver.LookupCNAME(ctx2, domain) } diff --git a/gobusterfuzz/gobusterfuzz.go b/gobusterfuzz/gobusterfuzz.go index 0f6aafb2..3b8cabf5 100644 --- a/gobusterfuzz/gobusterfuzz.go +++ b/gobusterfuzz/gobusterfuzz.go @@ -31,7 +31,7 @@ type GobusterFuzz struct { } // NewGobusterFuzz creates a new initialized GobusterFuzz -func NewGobusterFuzz(cont context.Context, globalopts *libgobuster.Options, opts *OptionsFuzz) (*GobusterFuzz, error) { +func NewGobusterFuzz(globalopts *libgobuster.Options, opts *OptionsFuzz) (*GobusterFuzz, error) { if globalopts == nil { return nil, fmt.Errorf("please provide valid global options") } @@ -62,7 +62,7 @@ func NewGobusterFuzz(cont context.Context, globalopts *libgobuster.Options, opts Method: opts.Method, } - h, err := libgobuster.NewHTTPClient(cont, &httpOpts) + h, err := libgobuster.NewHTTPClient(&httpOpts) if err != nil { return nil, err } @@ -81,14 +81,14 @@ func (d *GobusterFuzz) RequestsPerRun() int { } // PreRun is the pre run implementation of gobusterfuzz -func (d *GobusterFuzz) PreRun() error { +func (d *GobusterFuzz) PreRun(ctx context.Context) error { return nil } // Run is the process implementation of gobusterfuzz -func (d *GobusterFuzz) Run(word string, resChannel chan<- libgobuster.Result) error { +func (d *GobusterFuzz) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { workingURL := strings.ReplaceAll(d.options.URL, "FUZZ", word) - statusCode, size, _, _, err := d.http.Request(workingURL, libgobuster.RequestOptions{}) + statusCode, size, _, _, err := d.http.Request(ctx, workingURL, libgobuster.RequestOptions{}) if err != nil { return err } diff --git a/gobusters3/gobusters3.go b/gobusters3/gobusters3.go index 440774ec..7addb9e6 100644 --- a/gobusters3/gobusters3.go +++ b/gobusters3/gobusters3.go @@ -23,7 +23,7 @@ type GobusterS3 struct { } // NewGobusterS3 creates a new initialized GobusterS3 -func NewGobusterS3(cont context.Context, globalopts *libgobuster.Options, opts *OptionsS3) (*GobusterS3, error) { +func NewGobusterS3(globalopts *libgobuster.Options, opts *OptionsS3) (*GobusterS3, error) { if globalopts == nil { return nil, fmt.Errorf("please provide valid global options") } @@ -50,7 +50,7 @@ func NewGobusterS3(cont context.Context, globalopts *libgobuster.Options, opts * FollowRedirect: true, } - h, err := libgobuster.NewHTTPClient(cont, &httpOpts) + h, err := libgobuster.NewHTTPClient(&httpOpts) if err != nil { return nil, err } @@ -71,19 +71,19 @@ func (s *GobusterS3) RequestsPerRun() int { } // PreRun is the pre run implementation of GobusterS3 -func (s *GobusterS3) PreRun() error { +func (s *GobusterS3) PreRun(ctx context.Context) error { return nil } // Run is the process implementation of GobusterS3 -func (s *GobusterS3) Run(word string, resChannel chan<- libgobuster.Result) error { +func (s *GobusterS3) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { // only check for valid bucket names if !s.isValidBucketName(word) { return nil } bucketURL := fmt.Sprintf("https://%s.s3.amazonaws.com/?max-keys=%d", word, s.options.MaxFilesToList) - status, _, _, body, err := s.http.Request(bucketURL, libgobuster.RequestOptions{ReturnBody: true}) + status, _, _, body, err := s.http.Request(ctx, bucketURL, libgobuster.RequestOptions{ReturnBody: true}) if err != nil { return err } diff --git a/gobustervhost/gobustervhost.go b/gobustervhost/gobustervhost.go index 2453499b..3013fba4 100644 --- a/gobustervhost/gobustervhost.go +++ b/gobustervhost/gobustervhost.go @@ -24,7 +24,7 @@ type GobusterVhost struct { } // NewGobusterVhost creates a new initialized GobusterDir -func NewGobusterVhost(cont context.Context, globalopts *libgobuster.Options, opts *OptionsVhost) (*GobusterVhost, error) { +func NewGobusterVhost(globalopts *libgobuster.Options, opts *OptionsVhost) (*GobusterVhost, error) { if globalopts == nil { return nil, fmt.Errorf("please provide valid global options") } @@ -55,7 +55,7 @@ func NewGobusterVhost(cont context.Context, globalopts *libgobuster.Options, opt Method: opts.Method, } - h, err := libgobuster.NewHTTPClient(cont, &httpOpts) + h, err := libgobuster.NewHTTPClient(&httpOpts) if err != nil { return nil, err } @@ -74,7 +74,7 @@ func (v *GobusterVhost) RequestsPerRun() int { } // PreRun is the pre run implementation of gobusterdir -func (v *GobusterVhost) PreRun() error { +func (v *GobusterVhost) PreRun(ctx context.Context) error { // add trailing slash if !strings.HasSuffix(v.options.URL, "/") { v.options.URL = fmt.Sprintf("%s/", v.options.URL) @@ -87,7 +87,7 @@ func (v *GobusterVhost) PreRun() error { v.domain = urlParsed.Host // request default vhost for baseline1 - _, _, _, tmp, err := v.http.Request(v.options.URL, libgobuster.RequestOptions{ReturnBody: true}) + _, _, _, tmp, err := v.http.Request(ctx, v.options.URL, libgobuster.RequestOptions{ReturnBody: true}) if err != nil { return fmt.Errorf("unable to connect to %s: %w", v.options.URL, err) } @@ -95,7 +95,7 @@ func (v *GobusterVhost) PreRun() error { // request non existent vhost for baseline2 subdomain := fmt.Sprintf("%s.%s", uuid.New(), v.domain) - _, _, _, tmp, err = v.http.Request(v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) + _, _, _, tmp, err = v.http.Request(ctx, v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) if err != nil { return fmt.Errorf("unable to connect to %s: %w", v.options.URL, err) } @@ -104,7 +104,7 @@ func (v *GobusterVhost) PreRun() error { } // Run is the process implementation of gobusterdir -func (v *GobusterVhost) Run(word string, resChannel chan<- libgobuster.Result) error { +func (v *GobusterVhost) Run(ctx context.Context, word string, resChannel chan<- libgobuster.Result) error { var subdomain string if v.options.AppendDomain { subdomain = fmt.Sprintf("%s.%s", word, v.domain) @@ -112,7 +112,7 @@ func (v *GobusterVhost) Run(word string, resChannel chan<- libgobuster.Result) e // wordlist needs to include full domains subdomain = word } - status, size, header, body, err := v.http.Request(v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) + status, size, header, body, err := v.http.Request(ctx, v.options.URL, libgobuster.RequestOptions{Host: subdomain, ReturnBody: true}) if err != nil { return err } diff --git a/helper/useragents.go b/helper/useragents.go index 64d51fe3..5d9f1dd3 100644 --- a/helper/useragents.go +++ b/helper/useragents.go @@ -5,6 +5,7 @@ import ( "math/big" ) +// molint:gochecknoglobals var userAgents = [...]string{ "Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0", diff --git a/libgobuster/http.go b/libgobuster/http.go index 9f0ad5df..38e11aa2 100644 --- a/libgobuster/http.go +++ b/libgobuster/http.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strings" @@ -21,7 +20,6 @@ type HTTPHeader struct { // HTTPClient represents a http object type HTTPClient struct { client *http.Client - context context.Context userAgent string defaultUserAgent string username string @@ -40,7 +38,7 @@ type RequestOptions struct { } // NewHTTPClient returns a new HTTPClient -func NewHTTPClient(c context.Context, opt *HTTPOptions) (*HTTPClient, error) { +func NewHTTPClient(opt *HTTPOptions) (*HTTPClient, error) { var proxyURLFunc func(*http.Request) (*url.URL, error) var client HTTPClient proxyURLFunc = http.ProxyFromEnvironment @@ -77,7 +75,6 @@ func NewHTTPClient(c context.Context, opt *HTTPOptions) (*HTTPClient, error) { InsecureSkipVerify: opt.NoTLSValidation, }, }} - client.context = c client.username = opt.Username client.password = opt.Password client.userAgent = opt.UserAgent @@ -100,11 +97,11 @@ func NewHTTPClient(c context.Context, opt *HTTPOptions) (*HTTPClient, error) { // Request makes an http request and returns the status, the content length, the headers, the body and an error // if you want the body returned set the corresponding property inside RequestOptions -func (client *HTTPClient) Request(fullURL string, opts RequestOptions) (*int, int64, http.Header, []byte, error) { - resp, err := client.makeRequest(fullURL, opts.Host, opts.Body) +func (client *HTTPClient) Request(ctx context.Context, fullURL string, opts RequestOptions) (*int, int64, http.Header, []byte, error) { + resp, err := client.makeRequest(ctx, fullURL, opts.Host, opts.Body) if err != nil { // ignore context canceled errors - if errors.Is(client.context.Err(), context.Canceled) { + if errors.Is(ctx.Err(), context.Canceled) { return nil, 0, nil, nil, nil } return nil, 0, nil, nil, err @@ -114,7 +111,7 @@ func (client *HTTPClient) Request(fullURL string, opts RequestOptions) (*int, in var body []byte var length int64 if opts.ReturnBody { - body, err = ioutil.ReadAll(resp.Body) + body, err = io.ReadAll(resp.Body) if err != nil { return nil, 0, nil, nil, fmt.Errorf("could not read body %w", err) } @@ -122,7 +119,7 @@ func (client *HTTPClient) Request(fullURL string, opts RequestOptions) (*int, in } else { // DO NOT REMOVE! // absolutely needed so golang will reuse connections! - length, err = io.Copy(ioutil.Discard, resp.Body) + length, err = io.Copy(io.Discard, resp.Body) if err != nil { return nil, 0, nil, nil, err } @@ -131,14 +128,14 @@ func (client *HTTPClient) Request(fullURL string, opts RequestOptions) (*int, in return &resp.StatusCode, length, resp.Header, body, nil } -func (client *HTTPClient) makeRequest(fullURL, host string, data io.Reader) (*http.Response, error) { +func (client *HTTPClient) makeRequest(ctx context.Context, fullURL, host string, data io.Reader) (*http.Response, error) { req, err := http.NewRequest(client.method, fullURL, data) if err != nil { return nil, err } // add the context so we can easily cancel out - req = req.WithContext(client.context) + req = req.WithContext(ctx) if client.cookies != "" { req.Header.Set("Cookie", client.cookies) diff --git a/libgobuster/http_test.go b/libgobuster/http_test.go index a1e48ab8..1602be29 100644 --- a/libgobuster/http_test.go +++ b/libgobuster/http_test.go @@ -51,11 +51,11 @@ func TestRequest(t *testing.T) { h := httpServerT(t, ret) defer h.Close() var o HTTPOptions - c, err := NewHTTPClient(context.Background(), &o) + c, err := NewHTTPClient(&o) if err != nil { t.Fatalf("Got Error: %v", err) } - status, length, _, body, err := c.Request(h.URL, RequestOptions{ReturnBody: true}) + status, length, _, body, err := c.Request(context.Background(), h.URL, RequestOptions{ReturnBody: true}) if err != nil { t.Fatalf("Got Error: %v", err) } @@ -78,12 +78,12 @@ func BenchmarkRequestWithoutBody(b *testing.B) { h := httpServerB(b, r) defer h.Close() var o HTTPOptions - c, err := NewHTTPClient(context.Background(), &o) + c, err := NewHTTPClient(&o) if err != nil { b.Fatalf("Got Error: %v", err) } for x := 0; x < b.N; x++ { - _, _, _, _, err := c.Request(h.URL, RequestOptions{ReturnBody: false}) + _, _, _, _, err := c.Request(context.Background(), h.URL, RequestOptions{ReturnBody: false}) if err != nil { b.Fatalf("Got Error: %v", err) } @@ -98,12 +98,12 @@ func BenchmarkRequestWitBody(b *testing.B) { h := httpServerB(b, r) defer h.Close() var o HTTPOptions - c, err := NewHTTPClient(context.Background(), &o) + c, err := NewHTTPClient(&o) if err != nil { b.Fatalf("Got Error: %v", err) } for x := 0; x < b.N; x++ { - _, _, _, _, err := c.Request(h.URL, RequestOptions{ReturnBody: true}) + _, _, _, _, err := c.Request(context.Background(), h.URL, RequestOptions{ReturnBody: true}) if err != nil { b.Fatalf("Got Error: %v", err) } @@ -119,7 +119,7 @@ func BenchmarkNewHTTPClient(b *testing.B) { defer h.Close() var o HTTPOptions for x := 0; x < b.N; x++ { - _, err := NewHTTPClient(context.Background(), &o) + _, err := NewHTTPClient(&o) if err != nil { b.Fatalf("Got Error: %v", err) } diff --git a/libgobuster/interfaces.go b/libgobuster/interfaces.go index a50b9bf0..3e0e5f68 100644 --- a/libgobuster/interfaces.go +++ b/libgobuster/interfaces.go @@ -1,11 +1,13 @@ package libgobuster +import "context" + // GobusterPlugin is an interface which plugins must implement type GobusterPlugin interface { Name() string RequestsPerRun() int - PreRun() error - Run(string, chan<- Result) error + PreRun(context.Context) error + Run(context.Context, string, chan<- Result) error GetConfigString() (string, error) } diff --git a/libgobuster/libgobuster.go b/libgobuster/libgobuster.go index e623f220..67b5fef4 100644 --- a/libgobuster/libgobuster.go +++ b/libgobuster/libgobuster.go @@ -26,7 +26,6 @@ type ResultToStringFunc func(*Gobuster, *Result) (*string, error) // Gobuster is the main object when creating a new run type Gobuster struct { Opts *Options - context context.Context RequestsExpected int RequestsIssued int RequestsCountMutex *sync.RWMutex @@ -38,12 +37,11 @@ type Gobuster struct { } // NewGobuster returns a new Gobuster object -func NewGobuster(c context.Context, opts *Options, plugin GobusterPlugin) (*Gobuster, error) { +func NewGobuster(opts *Options, plugin GobusterPlugin) (*Gobuster, error) { var g Gobuster g.Opts = opts g.plugin = plugin g.RequestsCountMutex = new(sync.RWMutex) - g.context = c g.resultChan = make(chan Result) g.errorChan = make(chan error) g.LogInfo = log.New(os.Stdout, "", log.LstdFlags) @@ -68,11 +66,11 @@ func (g *Gobuster) incrementRequests() { g.RequestsCountMutex.Unlock() } -func (g *Gobuster) worker(wordChan <-chan string, wg *sync.WaitGroup) { +func (g *Gobuster) worker(ctx context.Context, wordChan <-chan string, wg *sync.WaitGroup) { defer wg.Done() for { select { - case <-g.context.Done(): + case <-ctx.Done(): return case word, ok := <-wordChan: // worker finished @@ -88,7 +86,7 @@ func (g *Gobuster) worker(wordChan <-chan string, wg *sync.WaitGroup) { } // Mode-specific processing - err := g.plugin.Run(wordCleaned, g.resultChan) + err := g.plugin.Run(ctx, wordCleaned, g.resultChan) if err != nil { // do not exit and continue g.errorChan <- err @@ -96,7 +94,7 @@ func (g *Gobuster) worker(wordChan <-chan string, wg *sync.WaitGroup) { } select { - case <-g.context.Done(): + case <-ctx.Done(): case <-time.After(g.Opts.Delay): } } @@ -137,13 +135,13 @@ func (g *Gobuster) getWordlist() (*bufio.Scanner, error) { return bufio.NewScanner(wordlist), nil } -// Start the busting of the website with the given +// Run the busting of the website with the given // set of settings from the command line. -func (g *Gobuster) Start() error { +func (g *Gobuster) Run(ctx context.Context) error { defer close(g.resultChan) defer close(g.errorChan) - if err := g.plugin.PreRun(); err != nil { + if err := g.plugin.PreRun(ctx); err != nil { return err } @@ -155,7 +153,7 @@ func (g *Gobuster) Start() error { // Create goroutines for each of the number of threads // specified. for i := 0; i < g.Opts.Threads; i++ { - go g.worker(wordChan, &workerGroup) + go g.worker(ctx, wordChan, &workerGroup) } scanner, err := g.getWordlist() @@ -166,7 +164,7 @@ func (g *Gobuster) Start() error { Scan: for scanner.Scan() { select { - case <-g.context.Done(): + case <-ctx.Done(): break Scan default: word := scanner.Text() @@ -177,7 +175,7 @@ Scan: for _, w := range perms { select { // need to check here too otherwise wordChan will block - case <-g.context.Done(): + case <-ctx.Done(): break Scan case wordChan <- w: }