diff --git a/README.md b/README.md index 5974af5..2059b29 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Usage of ./ffuf: -r Follow redirects -s Do not print additional information (silent mode) -sa - Stop on all error cases. Implies -sf and -se + Stop on all error cases. Implies -sf and -se. Also stops on spurious 429 response codes. -se Stop on spurious errors -sf @@ -194,6 +194,7 @@ The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard l - New - Changed - Limit the use of `-e` (extensions) to a single keyword: FUZZ + - Take 429 responses into account when -sa (stop on all error cases) is used - v0.12 - New @@ -206,7 +207,7 @@ The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard l - SIGTERM monitoring, in order to catch keyboard interrupts an such, to be able to write `-o` files before exiting. - Changed - Fixed a bug in the default multi wordlist mode - - Fixed JSON output regression, where all the input data was always encoded in base64 + - Fixed JSON output regression, where all the input data was always encoded in base64 - `--debug-log` no correctly logs connection errors - Removed `-l` flag in favor of `-v` - More verbose information in banner shown in startup. diff --git a/main.go b/main.go index 8437545..93b81ad 100644 --- a/main.go +++ b/main.go @@ -96,7 +96,7 @@ func main() { flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)") flag.BoolVar(&conf.StopOn403, "sf", false, "Stop when > 95% of responses return 403 Forbidden") flag.BoolVar(&conf.StopOnErrors, "se", false, "Stop on spurious errors") - flag.BoolVar(&conf.StopOnAll, "sa", false, "Stop on all error cases. Implies -sf and -se") + flag.BoolVar(&conf.StopOnAll, "sa", false, "Stop on all error cases. Implies -sf and -se. Also stops on spurious 429 response codes.") flag.BoolVar(&conf.FollowRedirects, "r", false, "Follow redirects") flag.BoolVar(&conf.AutoCalibration, "ac", false, "Automatically calibrate filtering options") flag.Var(&opts.AutoCalibrationStrings, "acc", "Custom auto-calibration string. Can be used multiple times. Implies -ac") diff --git a/pkg/ffuf/job.go b/pkg/ffuf/job.go index 0d409a3..7517df2 100644 --- a/pkg/ffuf/job.go +++ b/pkg/ffuf/job.go @@ -24,6 +24,7 @@ type Job struct { Total int Running bool Count403 int + Count429 int Error string startTime time.Time } @@ -52,6 +53,13 @@ func (j *Job) inc403() { j.Count403++ } +// inc429 increments the 429 response counter +func (j *Job) inc429() { + j.ErrorMutex.Lock() + defer j.ErrorMutex.Unlock() + j.Count429++ +} + //resetSpuriousErrors resets the spurious error counter func (j *Job) resetSpuriousErrors() { j.ErrorMutex.Lock() @@ -197,11 +205,19 @@ func (j *Job) runTask(input map[string][]byte, position int, retried bool) { j.resetSpuriousErrors() } if j.Config.StopOn403 || j.Config.StopOnAll { - // Incremnt Forbidden counter if we encountered one + // Increment Forbidden counter if we encountered one if resp.StatusCode == 403 { j.inc403() } } + if j.Config.StopOnAll { + // increment 429 counter if the response code is 429 + if j.Config.StopOnAll { + if resp.StatusCode == 429 { + j.inc429() + } + } + } if j.isMatch(resp) { j.Output.Result(resp) // Refresh the progress indicator as we printed something out @@ -249,6 +265,7 @@ func (j *Job) CalibrateResponses() ([]Response, error) { return results, nil } +// CheckStop stops the job if stopping conditions are met func (j *Job) CheckStop() { if j.Counter > 50 { // We have enough samples @@ -267,6 +284,11 @@ func (j *Job) CheckStop() { } } + if j.Config.StopOnAll && (float64(j.Count429)/float64(j.Counter) > 0.2) { + // Over 20% of responses are 429 + j.Error = "Getting an unusual amount of 429 responses, exiting." + j.Stop() + } } }