From efcea607c6424f360af64afaf737ecdfe8dfc71a Mon Sep 17 00:00:00 2001 From: 0xyy66 Date: Thu, 3 Oct 2024 10:37:48 +0200 Subject: [PATCH] Add exclude-hostname-length flag --- cli/cmd/vhost.go | 6 ++++++ gobustervhost/gobustervhost.go | 12 +++++++++++- gobustervhost/options.go | 9 +++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cli/cmd/vhost.go b/cli/cmd/vhost.go index c707750b..3091a9c1 100644 --- a/cli/cmd/vhost.go +++ b/cli/cmd/vhost.go @@ -80,6 +80,11 @@ func parseVhostOptions() (*libgobuster.Options, *gobustervhost.OptionsVhost, err return nil, nil, fmt.Errorf("invalid value for domain: %w", err) } + pluginOpts.ExcludeHostnameLength, err = cmdVhost.Flags().GetBool("exclude-hostname-length") + if err != nil { + return nil, nil, fmt.Errorf("invalid value for exclude-hostname-length: %w", err) + } + return globalopts, pluginOpts, nil } @@ -95,6 +100,7 @@ func init() { } 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.") cmdVhost.Flags().String("exclude-length", "", "exclude the following content lengths (completely ignores the status). You can separate multiple lengths by comma and it also supports ranges like 203-206") + cmdVhost.Flags().BoolP("exclude-hostname-length", "d", false, "Automatically adjust exclude-length based on dynamic hostname length in responses") 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") cmdVhost.PersistentPreRun = func(cmd *cobra.Command, args []string) { diff --git a/gobustervhost/gobustervhost.go b/gobustervhost/gobustervhost.go index d3d8059b..9740b81d 100644 --- a/gobustervhost/gobustervhost.go +++ b/gobustervhost/gobustervhost.go @@ -111,12 +111,18 @@ func (v *GobusterVhost) PreRun(ctx context.Context, progress *libgobuster.Progre // ProcessWord is the process implementation of gobusterdir func (v *GobusterVhost) ProcessWord(ctx context.Context, word string, progress *libgobuster.Progress) error { var subdomain string + var wordLength int if v.options.AppendDomain { subdomain = fmt.Sprintf("%s.%s", word, v.domain) } else { // wordlist needs to include full domains subdomain = word } + if v.options.ExcludeHostnameLength { + wordLength = len(word) + } else { + wordLength = 0 + } tries := 1 if v.options.RetryOnTimeout && v.options.RetryAttempts > 0 { @@ -151,7 +157,7 @@ func (v *GobusterVhost) ProcessWord(ctx context.Context, word string, progress * // subdomain must not match default vhost and non existent vhost // or verbose mode is enabled found := body != nil && !bytes.Equal(body, v.normalBody) && !bytes.Equal(body, v.abnormalBody) - if (found && !v.options.ExcludeLengthParsed.Contains(int(size))) || v.globalopts.Verbose { + if (found && !v.options.ExcludeLengthParsed.Contains(int(size)-wordLength)) || v.globalopts.Verbose { resultStatus := false if found { resultStatus = true @@ -253,6 +259,10 @@ func (v *GobusterVhost) GetConfigString() (string, error) { } } + if _, err := fmt.Fprintf(tw, "[+] Exclude Hostname Length:\t%t\n", v.options.ExcludeHostnameLength); err != nil { + return "", err + } + if err := tw.Flush(); err != nil { return "", fmt.Errorf("error on tostring: %w", err) } diff --git a/gobustervhost/options.go b/gobustervhost/options.go index a5090308..55302cc9 100644 --- a/gobustervhost/options.go +++ b/gobustervhost/options.go @@ -7,10 +7,11 @@ import ( // OptionsVhost is the struct to hold all options for this plugin type OptionsVhost struct { libgobuster.HTTPOptions - AppendDomain bool - ExcludeLength string - ExcludeLengthParsed libgobuster.Set[int] - Domain string + AppendDomain bool + ExcludeLength string + ExcludeLengthParsed libgobuster.Set[int] + Domain string + ExcludeHostnameLength bool } // NewOptionsVhost returns a new initialized OptionsVhost