Skip to content

Commit

Permalink
Dev (#362)
Browse files Browse the repository at this point in the history
  • Loading branch information
firefart authored Oct 29, 2022
1 parent 64a5d22 commit b90dd32
Show file tree
Hide file tree
Showing 24 changed files with 406 additions and 159 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ All funds that are donated to this project will be donated to charity. A full lo

# Changes

## 3.3

- Support TLS client certificates / mtl
- support loading extensions from file
- support fuzzing POST body, HTTP headers and basic auth
- new option to not canonicalize header names

## 3.2

- Use go 1.19
Expand Down Expand Up @@ -479,7 +486,7 @@ https://buffered.io/categories
### Options

```text
Uses VHOST enumeration mode (you most probably want to use the IP adress as the URL parameter
Uses VHOST enumeration mode (you most probably want to use the IP address as the URL parameter)
Usage:
gobuster vhost [flags]
Expand Down
85 changes: 51 additions & 34 deletions cli/cmd/dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,98 +42,114 @@ func parseDirOptions() (*libgobuster.Options, *gobusterdir.OptionsDir, error) {
return nil, nil, err
}

plugin := gobusterdir.NewOptionsDir()
pluginOpts := gobusterdir.NewOptionsDir()

httpOpts, err := parseCommonHTTPOptions(cmdDir)
if err != nil {
return nil, nil, err
}
plugin.Password = httpOpts.Password
plugin.URL = httpOpts.URL
plugin.UserAgent = httpOpts.UserAgent
plugin.Username = httpOpts.Username
plugin.Proxy = httpOpts.Proxy
plugin.Cookies = httpOpts.Cookies
plugin.Timeout = httpOpts.Timeout
plugin.FollowRedirect = httpOpts.FollowRedirect
plugin.NoTLSValidation = httpOpts.NoTLSValidation
plugin.Headers = httpOpts.Headers
plugin.Method = httpOpts.Method
plugin.RetryOnTimeout = httpOpts.RetryOnTimeout
plugin.RetryAttempts = httpOpts.RetryAttempts

plugin.Extensions, err = cmdDir.Flags().GetString("extensions")
pluginOpts.Password = httpOpts.Password
pluginOpts.URL = httpOpts.URL
pluginOpts.UserAgent = httpOpts.UserAgent
pluginOpts.Username = httpOpts.Username
pluginOpts.Proxy = httpOpts.Proxy
pluginOpts.Cookies = httpOpts.Cookies
pluginOpts.Timeout = httpOpts.Timeout
pluginOpts.FollowRedirect = httpOpts.FollowRedirect
pluginOpts.NoTLSValidation = httpOpts.NoTLSValidation
pluginOpts.Headers = httpOpts.Headers
pluginOpts.Method = httpOpts.Method
pluginOpts.RetryOnTimeout = httpOpts.RetryOnTimeout
pluginOpts.RetryAttempts = httpOpts.RetryAttempts
pluginOpts.TLSCertificate = httpOpts.TLSCertificate
pluginOpts.NoCanonicalizeHeaders = httpOpts.NoCanonicalizeHeaders

pluginOpts.Extensions, err = cmdDir.Flags().GetString("extensions")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for extensions: %w", err)
}
ret, err := helper.ParseExtensions(plugin.Extensions)

ret, err := helper.ParseExtensions(pluginOpts.Extensions)
if err != nil {
return nil, nil, fmt.Errorf("invalid value for extensions: %w", err)
}
plugin.ExtensionsParsed = ret
pluginOpts.ExtensionsParsed = ret

pluginOpts.ExtensionsFile, err = cmdDir.Flags().GetString("extensions-file")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for extensions file: %w", err)
}

if pluginOpts.ExtensionsFile != "" {
extensions, err := helper.ParseExtensionsFile(pluginOpts.ExtensionsFile)
if err != nil {
return nil, nil, fmt.Errorf("invalid value for extensions file: %w", err)
}
pluginOpts.ExtensionsParsed.AddRange(extensions)
}

// parse normal status codes
plugin.StatusCodes, err = cmdDir.Flags().GetString("status-codes")
pluginOpts.StatusCodes, err = cmdDir.Flags().GetString("status-codes")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for status-codes: %w", err)
}
ret2, err := helper.ParseCommaSeparatedInt(plugin.StatusCodes)
ret2, err := helper.ParseCommaSeparatedInt(pluginOpts.StatusCodes)
if err != nil {
return nil, nil, fmt.Errorf("invalid value for status-codes: %w", err)
}
plugin.StatusCodesParsed = ret2
pluginOpts.StatusCodesParsed = ret2

// blacklist will override the normal status codes
plugin.StatusCodesBlacklist, err = cmdDir.Flags().GetString("status-codes-blacklist")
pluginOpts.StatusCodesBlacklist, err = cmdDir.Flags().GetString("status-codes-blacklist")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for status-codes-blacklist: %w", err)
}
ret3, err := helper.ParseCommaSeparatedInt(plugin.StatusCodesBlacklist)
ret3, err := helper.ParseCommaSeparatedInt(pluginOpts.StatusCodesBlacklist)
if err != nil {
return nil, nil, fmt.Errorf("invalid value for status-codes-blacklist: %w", err)
}
plugin.StatusCodesBlacklistParsed = ret3
pluginOpts.StatusCodesBlacklistParsed = ret3

if plugin.StatusCodes != "" && plugin.StatusCodesBlacklist != "" {
if pluginOpts.StatusCodes != "" && pluginOpts.StatusCodesBlacklist != "" {
return nil, nil, fmt.Errorf("status-codes (%q) and status-codes-blacklist (%q) are both set - please set only one. status-codes-blacklist is set by default so you might want to disable it by supplying an empty string.",
plugin.StatusCodes, plugin.StatusCodesBlacklist)
pluginOpts.StatusCodes, pluginOpts.StatusCodesBlacklist)
}

if plugin.StatusCodes == "" && plugin.StatusCodesBlacklist == "" {
if pluginOpts.StatusCodes == "" && pluginOpts.StatusCodesBlacklist == "" {
return nil, nil, fmt.Errorf("status-codes and status-codes-blacklist are both not set, please set one")
}

plugin.UseSlash, err = cmdDir.Flags().GetBool("add-slash")
pluginOpts.UseSlash, err = cmdDir.Flags().GetBool("add-slash")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for add-slash: %w", err)
}

plugin.Expanded, err = cmdDir.Flags().GetBool("expanded")
pluginOpts.Expanded, err = cmdDir.Flags().GetBool("expanded")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for expanded: %w", err)
}

plugin.NoStatus, err = cmdDir.Flags().GetBool("no-status")
pluginOpts.NoStatus, err = cmdDir.Flags().GetBool("no-status")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for no-status: %w", err)
}

plugin.HideLength, err = cmdDir.Flags().GetBool("hide-length")
pluginOpts.HideLength, err = cmdDir.Flags().GetBool("hide-length")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for hide-length: %w", err)
}

plugin.DiscoverBackup, err = cmdDir.Flags().GetBool("discover-backup")
pluginOpts.DiscoverBackup, err = cmdDir.Flags().GetBool("discover-backup")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for discover-backup: %w", err)
}

plugin.ExcludeLength, err = cmdDir.Flags().GetIntSlice("exclude-length")
pluginOpts.ExcludeLength, err = cmdDir.Flags().GetIntSlice("exclude-length")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for excludelength: %w", err)
}

return globalopts, plugin, nil
return globalopts, pluginOpts, nil
}

// nolint:gochecknoinits
Expand All @@ -150,6 +166,7 @@ func init() {
cmdDir.Flags().StringP("status-codes", "s", "", "Positive status codes (will be overwritten with status-codes-blacklist if set)")
cmdDir.Flags().StringP("status-codes-blacklist", "b", "404", "Negative status codes (will override status-codes if set)")
cmdDir.Flags().StringP("extensions", "x", "", "File extension(s) to search for")
cmdDir.Flags().StringP("extensions-file", "X", "", "Read file extension(s) to search from the file")
cmdDir.Flags().BoolP("expanded", "e", false, "Expanded mode, print full URLs")
cmdDir.Flags().BoolP("no-status", "n", false, "Don't print status codes")
cmdDir.Flags().Bool("hide-length", false, "Hide the length of the body in the output")
Expand Down
18 changes: 9 additions & 9 deletions cli/cmd/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,43 +42,43 @@ func parseDNSOptions() (*libgobuster.Options, *gobusterdns.OptionsDNS, error) {
if err != nil {
return nil, nil, err
}
plugin := gobusterdns.NewOptionsDNS()
pluginOpts := gobusterdns.NewOptionsDNS()

plugin.Domain, err = cmdDNS.Flags().GetString("domain")
pluginOpts.Domain, err = cmdDNS.Flags().GetString("domain")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for domain: %w", err)
}

plugin.ShowIPs, err = cmdDNS.Flags().GetBool("show-ips")
pluginOpts.ShowIPs, err = cmdDNS.Flags().GetBool("show-ips")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for show-ips: %w", err)
}

plugin.ShowCNAME, err = cmdDNS.Flags().GetBool("show-cname")
pluginOpts.ShowCNAME, err = cmdDNS.Flags().GetBool("show-cname")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for show-cname: %w", err)
}

plugin.WildcardForced, err = cmdDNS.Flags().GetBool("wildcard")
pluginOpts.WildcardForced, err = cmdDNS.Flags().GetBool("wildcard")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for wildcard: %w", err)
}

plugin.Timeout, err = cmdDNS.Flags().GetDuration("timeout")
pluginOpts.Timeout, err = cmdDNS.Flags().GetDuration("timeout")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for timeout: %w", err)
}

plugin.Resolver, err = cmdDNS.Flags().GetString("resolver")
pluginOpts.Resolver, err = cmdDNS.Flags().GetString("resolver")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for resolver: %w", err)
}

if plugin.Resolver != "" && runtime.GOOS == "windows" {
if pluginOpts.Resolver != "" && runtime.GOOS == "windows" {
return nil, nil, fmt.Errorf("currently can not set custom dns resolver on windows. See https://golang.org/pkg/net/#hdr-Name_Resolution")
}

return globalopts, plugin, nil
return globalopts, pluginOpts, nil
}

// nolint:gochecknoinits
Expand Down
79 changes: 59 additions & 20 deletions cli/cmd/fuzz.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"strings"

"github.com/OJ/gobuster/v3/cli"
"github.com/OJ/gobuster/v3/gobusterfuzz"
Expand All @@ -21,6 +22,10 @@ func runFuzz(cmd *cobra.Command, args []string) error {
return fmt.Errorf("error on parsing arguments: %w", err)
}

if !containsFuzzKeyword(*pluginopts) {
return fmt.Errorf("please provide the %s keyword", gobusterfuzz.FuzzKeyword)
}

plugin, err := gobusterfuzz.NewGobusterFuzz(globalopts, pluginopts)
if err != nil {
return fmt.Errorf("error on creating gobusterfuzz: %w", err)
Expand All @@ -42,50 +47,57 @@ func parseFuzzOptions() (*libgobuster.Options, *gobusterfuzz.OptionsFuzz, error)
return nil, nil, err
}

plugin := gobusterfuzz.NewOptionsFuzz()
pluginOpts := gobusterfuzz.NewOptionsFuzz()

httpOpts, err := parseCommonHTTPOptions(cmdFuzz)
if err != nil {
return nil, nil, err
}
plugin.Password = httpOpts.Password
plugin.URL = httpOpts.URL
plugin.UserAgent = httpOpts.UserAgent
plugin.Username = httpOpts.Username
plugin.Proxy = httpOpts.Proxy
plugin.Cookies = httpOpts.Cookies
plugin.Timeout = httpOpts.Timeout
plugin.FollowRedirect = httpOpts.FollowRedirect
plugin.NoTLSValidation = httpOpts.NoTLSValidation
plugin.Headers = httpOpts.Headers
plugin.Method = httpOpts.Method
plugin.RetryOnTimeout = httpOpts.RetryOnTimeout
plugin.RetryAttempts = httpOpts.RetryAttempts
pluginOpts.Password = httpOpts.Password
pluginOpts.URL = httpOpts.URL
pluginOpts.UserAgent = httpOpts.UserAgent
pluginOpts.Username = httpOpts.Username
pluginOpts.Proxy = httpOpts.Proxy
pluginOpts.Cookies = httpOpts.Cookies
pluginOpts.Timeout = httpOpts.Timeout
pluginOpts.FollowRedirect = httpOpts.FollowRedirect
pluginOpts.NoTLSValidation = httpOpts.NoTLSValidation
pluginOpts.Headers = httpOpts.Headers
pluginOpts.Method = httpOpts.Method
pluginOpts.RetryOnTimeout = httpOpts.RetryOnTimeout
pluginOpts.RetryAttempts = httpOpts.RetryAttempts
pluginOpts.TLSCertificate = httpOpts.TLSCertificate
pluginOpts.NoCanonicalizeHeaders = httpOpts.NoCanonicalizeHeaders

// blacklist will override the normal status codes
plugin.ExcludedStatusCodes, err = cmdFuzz.Flags().GetString("excludestatuscodes")
pluginOpts.ExcludedStatusCodes, err = cmdFuzz.Flags().GetString("excludestatuscodes")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for excludestatuscodes: %w", err)
}
ret, err := helper.ParseCommaSeparatedInt(plugin.ExcludedStatusCodes)
ret, err := helper.ParseCommaSeparatedInt(pluginOpts.ExcludedStatusCodes)
if err != nil {
return nil, nil, fmt.Errorf("invalid value for excludestatuscodes: %w", err)
}
plugin.ExcludedStatusCodesParsed = ret
pluginOpts.ExcludedStatusCodesParsed = ret

plugin.ExcludeLength, err = cmdFuzz.Flags().GetIntSlice("exclude-length")
pluginOpts.ExcludeLength, err = cmdFuzz.Flags().GetIntSlice("exclude-length")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for excludelength: %w", err)
}

return globalopts, plugin, nil
pluginOpts.RequestBody, err = cmdFuzz.Flags().GetString("body")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for body: %w", err)
}

return globalopts, pluginOpts, nil
}

// nolint:gochecknoinits
func init() {
cmdFuzz = &cobra.Command{
Use: "fuzz",
Short: "Uses fuzzing mode",
Short: fmt.Sprintf("Uses fuzzing mode. Replaces the keyword %s in the URL, Headers and the request body", gobusterfuzz.FuzzKeyword),
RunE: runFuzz,
}

Expand All @@ -94,10 +106,37 @@ func init() {
}
cmdFuzz.Flags().StringP("excludestatuscodes", "b", "", "Negative status codes (will override statuscodes if set)")
cmdFuzz.Flags().IntSlice("exclude-length", []int{}, "exclude the following content length (completely ignores the status). Supply multiple times to exclude multiple sizes.")
cmdFuzz.Flags().StringP("body", "B", "", "Request body")

cmdFuzz.PersistentPreRun = func(cmd *cobra.Command, args []string) {
configureGlobalOptions()
}

rootCmd.AddCommand(cmdFuzz)
}

func containsFuzzKeyword(pluginopts gobusterfuzz.OptionsFuzz) bool {
if strings.Contains(pluginopts.URL, gobusterfuzz.FuzzKeyword) {
return true
}

if strings.Contains(pluginopts.RequestBody, gobusterfuzz.FuzzKeyword) {
return true
}

for _, h := range pluginopts.Headers {
if strings.Contains(h.Name, gobusterfuzz.FuzzKeyword) || strings.Contains(h.Value, gobusterfuzz.FuzzKeyword) {
return true
}
}

if strings.Contains(pluginopts.Username, gobusterfuzz.FuzzKeyword) {
return true
}

if strings.Contains(pluginopts.Password, gobusterfuzz.FuzzKeyword) {
return true
}

return false
}
1 change: 1 addition & 0 deletions cli/cmd/gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func parseGCSOptions() (*libgobuster.Options, *gobustergcs.OptionsGCS, error) {
pluginopts.NoTLSValidation = httpOpts.NoTLSValidation
pluginopts.RetryOnTimeout = httpOpts.RetryOnTimeout
pluginopts.RetryAttempts = httpOpts.RetryAttempts
pluginopts.TLSCertificate = httpOpts.TLSCertificate

pluginopts.MaxFilesToList, err = cmdGCS.Flags().GetInt("maxfiles")
if err != nil {
Expand Down
Loading

0 comments on commit b90dd32

Please sign in to comment.