mirror of
https://github.com/OJ/gobuster.git
synced 2024-05-06 11:16:05 +02:00
3bb230056c
* update to go 1.17 * more go 1.17 updates * update sponsors * update makefile * gitignore * remove todo * Fixed errors mixing with progress in stderr by removing progress string with \r * Added --retry option for dir, fuzz, s3 and vhost modes * first dev version * wording * fix retries * update help text * first work for #298 allow for a totalrequests change from within a plugin * use defer * ignore invalid control character urls * add goreleaser * gitignore * output color, better status printing * more color output * fix nil panics * Added support for Google Cloud Storage (GCS) bucket scanning. The scanning finds all public buckets listable by anonymous users * fix gcs module * update readme * go 1.18 * go mod tidy * makefile * readme * readme * better error message * use generics for set * use the new netip type * update version * colors * cspell * improve readability of GobusterVhost (#334) * improve readability of GobusterVhost * fix for the merge side effect * lint * update * update * more work * remove unused method * retries * colored output * Closes issue #349 (#356) * fix version * Closes issue #349 Co-authored-by: firefart <firefart@gmail.com> * Closes issue #315 (#359) * Closes issue #315 * Syntax fix * support mtls * readme * check for fuzz keyword * allow for http header fuzzing * better description * new option to not canonicalize header names * basic auth fuzzing * fix typo in vhost command (#361) * update * check error * error handling * dev * enable tls1.0 and 1.1 support * Bump golang.org/x/term from 0.1.0 to 0.2.0 (#369) Bumps [golang.org/x/term](https://github.com/golang/term) from 0.1.0 to 0.2.0. - [Release notes](https://github.com/golang/term/releases) - [Commits](https://github.com/golang/term/compare/v0.1.0...v0.2.0) --- updated-dependencies: - dependency-name: golang.org/x/term dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump golang.org/x/crypto from 0.1.0 to 0.2.0 (#368) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.1.0 to 0.2.0. - [Release notes](https://github.com/golang/crypto/releases) - [Commits](https://github.com/golang/crypto/compare/v0.1.0...v0.2.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Adds LF after the work end (#373) * typo * Reformat: Add `\n` after the end Co-authored-by: firefart <105281+firefart@users.noreply.github.com> * Bump golang.org/x/crypto from 0.2.0 to 0.3.0 (#374) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.2.0 to 0.3.0. - [Release notes](https://github.com/golang/crypto/releases) - [Commits](https://github.com/golang/crypto/compare/v0.2.0...v0.3.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump golang.org/x/crypto from 0.3.0 to 0.4.0 (#376) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.3.0 to 0.4.0. - [Release notes](https://github.com/golang/crypto/releases) - [Commits](https://github.com/golang/crypto/compare/v0.3.0...v0.4.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/checkout from 3.1.0 to 3.2.0 (#377) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3.1.0...v3.2.0) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * add tftp mode * better output on tftp mode * Bump goreleaser/goreleaser-action from 3 to 4 (#378) Bumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 3 to 4. - [Release notes](https://github.com/goreleaser/goreleaser-action/releases) - [Commits](https://github.com/goreleaser/goreleaser-action/compare/v3...v4) --- updated-dependencies: - dependency-name: goreleaser/goreleaser-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * readme Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: alexmozzhakov <5459149+alexmozzhakov@users.noreply.github.com> Co-authored-by: Nicolas Lykke Iversen <nlykkei@gmail.com> Co-authored-by: Neal Caffery <neal1991@sina.com> Co-authored-by: n30nx <22144985+n30nx@users.noreply.github.com> Co-authored-by: IPv4v6 <mail.ipv4v6@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: _Magenta_ <0_magenta_0@mail.ru>
174 lines
4.4 KiB
Go
174 lines
4.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/OJ/gobuster/v3/libgobuster"
|
|
)
|
|
|
|
const ruler = "==============================================================="
|
|
const cliProgressUpdate = 500 * time.Millisecond
|
|
|
|
func banner() {
|
|
fmt.Printf("Gobuster v%s\n", libgobuster.VERSION)
|
|
fmt.Println("by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)")
|
|
}
|
|
|
|
// resultWorker outputs the results as they come in. This needs to be a range and should not handle
|
|
// the context so the channel always has a receiver and libgobuster will not block.
|
|
func resultWorker(g *libgobuster.Gobuster, filename string, wg *sync.WaitGroup) {
|
|
defer wg.Done()
|
|
|
|
var f *os.File
|
|
var err error
|
|
if filename != "" {
|
|
f, err = os.Create(filename)
|
|
if err != nil {
|
|
g.LogError.Fatalf("error on creating output file: %v", err)
|
|
}
|
|
defer f.Close()
|
|
}
|
|
|
|
for r := range g.Progress.ResultChan {
|
|
s, err := r.ResultToString()
|
|
if err != nil {
|
|
g.LogError.Fatal(err)
|
|
}
|
|
if s != "" {
|
|
s = strings.TrimSpace(s)
|
|
_, _ = fmt.Printf("%s%s\n", TERMINAL_CLEAR_LINE, s)
|
|
if f != nil {
|
|
err = writeToFile(f, s)
|
|
if err != nil {
|
|
g.LogError.Fatalf("error on writing output file: %v", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// errorWorker outputs the errors as they come in. This needs to be a range and should not handle
|
|
// the context so the channel always has a receiver and libgobuster will not block.
|
|
func errorWorker(g *libgobuster.Gobuster, wg *sync.WaitGroup) {
|
|
defer wg.Done()
|
|
|
|
for e := range g.Progress.ErrorChan {
|
|
if !g.Opts.Quiet && !g.Opts.NoError {
|
|
g.LogError.Printf("[!] %s\n", e.Error())
|
|
}
|
|
}
|
|
}
|
|
|
|
// progressWorker outputs the progress every tick. It will stop once cancel() is called
|
|
// on the context
|
|
func progressWorker(ctx context.Context, g *libgobuster.Gobuster, wg *sync.WaitGroup) {
|
|
defer wg.Done()
|
|
|
|
tick := time.NewTicker(cliProgressUpdate)
|
|
|
|
for {
|
|
select {
|
|
case <-tick.C:
|
|
if !g.Opts.Quiet && !g.Opts.NoProgress {
|
|
requestsIssued := g.Progress.RequestsIssued()
|
|
requestsExpected := g.Progress.RequestsExpected()
|
|
if g.Opts.Wordlist == "-" {
|
|
s := fmt.Sprintf("%sProgress: %d", TERMINAL_CLEAR_LINE, requestsIssued)
|
|
_, _ = fmt.Fprint(os.Stderr, s)
|
|
// only print status if we already read in the wordlist
|
|
} else if requestsExpected > 0 {
|
|
s := fmt.Sprintf("%sProgress: %d / %d (%3.2f%%)", TERMINAL_CLEAR_LINE, requestsIssued, requestsExpected, float32(requestsIssued)*100.0/float32(requestsExpected))
|
|
_, _ = fmt.Fprint(os.Stderr, s)
|
|
}
|
|
}
|
|
case <-ctx.Done():
|
|
fmt.Println()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func writeToFile(f *os.File, output string) error {
|
|
_, err := f.WriteString(fmt.Sprintf("%s\n", output))
|
|
if err != nil {
|
|
return fmt.Errorf("[!] Unable to write to file %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Gobuster is the main entry point for the CLI
|
|
func Gobuster(ctx context.Context, opts *libgobuster.Options, plugin libgobuster.GobusterPlugin) error {
|
|
// Sanity checks
|
|
if opts == nil {
|
|
return fmt.Errorf("please provide valid options")
|
|
}
|
|
|
|
if plugin == nil {
|
|
return fmt.Errorf("please provide a valid plugin")
|
|
}
|
|
|
|
ctxCancel, cancel := context.WithCancel(ctx)
|
|
defer cancel()
|
|
|
|
gobuster, err := libgobuster.NewGobuster(opts, plugin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !opts.Quiet {
|
|
fmt.Println(ruler)
|
|
banner()
|
|
fmt.Println(ruler)
|
|
c, err := gobuster.GetConfigString()
|
|
if err != nil {
|
|
return fmt.Errorf("error on creating config string: %w", err)
|
|
}
|
|
fmt.Println(c)
|
|
fmt.Println(ruler)
|
|
gobuster.LogInfo.Printf("Starting gobuster in %s mode", plugin.Name())
|
|
fmt.Println(ruler)
|
|
}
|
|
|
|
// our waitgroup for all goroutines
|
|
// this ensures all goroutines are finished
|
|
// when we call wg.Wait()
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(1)
|
|
go resultWorker(gobuster, opts.OutputFilename, &wg)
|
|
|
|
wg.Add(1)
|
|
go errorWorker(gobuster, &wg)
|
|
|
|
if !opts.Quiet && !opts.NoProgress {
|
|
// if not quiet add a new workgroup entry and start the goroutine
|
|
wg.Add(1)
|
|
go progressWorker(ctxCancel, gobuster, &wg)
|
|
}
|
|
|
|
err = gobuster.Run(ctxCancel)
|
|
|
|
// call cancel func so progressWorker will exit (the only goroutine in this
|
|
// file using the context) and to free resources
|
|
cancel()
|
|
// wait for all spun up goroutines to finish (all have to call wg.Done())
|
|
wg.Wait()
|
|
|
|
// Late error checking to finish all threads
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !opts.Quiet {
|
|
fmt.Println(ruler)
|
|
gobuster.LogInfo.Println("Finished")
|
|
fmt.Println(ruler)
|
|
}
|
|
return nil
|
|
}
|