diff --git a/README.md b/README.md index 608a1de..e2c4073 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ ffuf -w /path/to/postdata.txt -X POST -d "username=admin\&password=FUZZ" https:/ To define the test case for ffuf, use the keyword `FUZZ` anywhere in the URL (`-u`), headers (`-H`), or POST data (`-d`). ``` + -D DirSearch style wordlist compatibility mode. Used in conjunction with -e flag. Replaces %EXT% in wordlist entry with each of the extensions provided by -e. -H "Name: Value" Header "Name: Value", separated by colon. Multiple -H flags are accepted. -V Show version information. @@ -78,6 +79,8 @@ To define the test case for ffuf, use the keyword `FUZZ` anywhere in the URL (`- -c Colorize output. -d string POST data. + -e string + Comma separated list of extensions to apply. Each extension provided will extend the wordlist entry once. -fc string Filter HTTP status codes from response -fr string @@ -138,6 +141,7 @@ The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard l - Erroring connections will be retried once - Error counter in status bar - New CLI flags: -se (stop on spurious errors) and -sa (stop on all errors, implies -se and -sf) + - New CLI flags: -e to provide a list of extensions to add to wordlist entries, and -D to provide DirSearch wordlist format compatibility. - v0.8 - New - New CLI flag to write output to a file in JSON format diff --git a/main.go b/main.go index 8247c56..45f3357 100644 --- a/main.go +++ b/main.go @@ -50,7 +50,8 @@ func main() { defer cancel() conf := ffuf.NewConfig(ctx) opts := cliOptions{} - flag.StringVar(&opts.extensions, "e", "", "extensions to bruteforce separated by a comma. `\"wordlist must contain %EXT%\"`") + flag.StringVar(&opts.extensions, "e", "", "List of extensions to apply. Each extension provided will extend the wordlist entry once.") + flag.BoolVar(&conf.DirSearchCompat, "D", false, "DirSearch style wordlist compatibility mode. Used in conjunction with -e flag. Replaces %EXT% in wordlist entry with each of the extensions provided by -e.") flag.Var(&opts.headers, "H", "Header `\"Name: Value\"`, separated by colon. Multiple -H flags are accepted.") flag.StringVar(&conf.Url, "u", "", "Target URL") flag.StringVar(&conf.Wordlist, "w", "", "Wordlist path") diff --git a/pkg/ffuf/config.go b/pkg/ffuf/config.go index f9061c6..7aa2b1a 100644 --- a/pkg/ffuf/config.go +++ b/pkg/ffuf/config.go @@ -19,6 +19,7 @@ type Config struct { StaticHeaders map[string]string FuzzHeaders map[string]string Extensions []string + DirSearchCompat bool Method string Url string TLSVerify bool @@ -59,5 +60,6 @@ func NewConfig(ctx context.Context) Config { conf.Filters = make([]FilterProvider, 0) conf.Delay = optRange{0, 0, false, false} conf.Extensions = make([]string, 0) + conf.DirSearchCompat = false return conf } diff --git a/pkg/input/wordlist.go b/pkg/input/wordlist.go index 631bd71..41a8f2a 100644 --- a/pkg/input/wordlist.go +++ b/pkg/input/wordlist.go @@ -72,11 +72,16 @@ func (w *WordlistInput) readFile(path string) error { var data [][]byte reader := bufio.NewScanner(file) for reader.Scan() { - if strings.Index(reader.Text(), "%EXT%") != -1 { - extensions := w.config.Extensions - for _, ext := range extensions { - contnt := strings.Replace(reader.Text(), "%EXT%", ext, -1) - data = append(data, []byte(contnt)) + if w.config.DirSearchCompat && len(w.config.Extensions) > 0 { + if strings.Index(reader.Text(), "%EXT%") != -1 { + for _, ext := range w.config.Extensions { + contnt := strings.Replace(reader.Text(), "%EXT%", ext, -1) + data = append(data, []byte(contnt)) + } + } + } else if len(w.config.Extensions) > 0 { + for _, ext := range w.config.Extensions { + data = append(data, []byte(reader.Text()+ext)) } } else { data = append(data, []byte(reader.Text()))