Merge pull request #2 from ffuf/delay

Add delay to requests
This commit is contained in:
Joona Hoikkala 2018-12-06 01:01:38 +02:00 committed by GitHub
commit 0818256e1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 7 deletions

View file

@ -71,9 +71,9 @@ 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`).
```
Usage of ./ffuf:
-H "Name: Value"
Header "Name: Value", separated by colon. Multiple -H flags are accepted.
-V Show version information.
-X string
HTTP method to use. (default "GET")
-c Colorize output.
@ -89,13 +89,15 @@ Usage of ./ffuf:
Filter by amount of words in response
-k Skip TLS identity verification (insecure)
-mc string
Match HTTP status codes from respose (default "200,204,301,302,307,401")
Match HTTP status codes from respose (default "200,204,301,302,307,401,403")
-mr string
Match regexp
-ms string
Match HTTP response size
-mw string
Match amount of words in response
-p delay
Seconds of delay between requests, or a range of random delay. For example "0.1" or "0.1-2.0"
-s Do not print additional information (silent mode)
-t int
Number of concurrent threads. (default 40)

37
main.go
View file

@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"os"
"strconv"
"strings"
"github.com/ffuf/ffuf/pkg/ffuf"
@ -15,6 +16,7 @@ import (
)
type cliOptions struct {
delay string
filterStatus string
filterSize string
filterRegexp string
@ -23,18 +25,18 @@ type cliOptions struct {
matcherSize string
matcherRegexp string
matcherWords string
headers headerFlags
headers multiStringFlag
showVersion bool
}
type headerFlags []string
type multiStringFlag []string
func (h *headerFlags) String() string {
func (m *multiStringFlag) String() string {
return ""
}
func (h *headerFlags) Set(value string) error {
*h = append(*h, value)
func (m *multiStringFlag) Set(value string) error {
*m = append(*m, value)
return nil
}
@ -47,6 +49,7 @@ func main() {
flag.StringVar(&conf.Url, "u", "", "Target URL")
flag.StringVar(&conf.Wordlist, "w", "", "Wordlist path")
flag.BoolVar(&conf.TLSSkipVerify, "k", false, "Skip TLS identity verification (insecure)")
flag.StringVar(&opts.delay, "p", "", "Seconds of `delay` between requests, or a range of random delay. For example \"0.1\" or \"0.1-2.0\"")
flag.StringVar(&opts.filterStatus, "fc", "", "Filter HTTP status codes from response")
flag.StringVar(&opts.filterSize, "fs", "", "Filter HTTP response size")
flag.StringVar(&opts.filterRegexp, "fr", "", "Filter regexp")
@ -111,6 +114,9 @@ func prepareConfig(parseOpts *cliOptions, conf *ffuf.Config) error {
//TODO: refactor in a proper flag library that can handle things like required flags
errs := ffuf.NewMultierror()
foundkeyword := false
var err error
var err2 error
if len(conf.Url) == 0 {
errs.Add(fmt.Errorf("-u flag is required"))
}
@ -138,6 +144,27 @@ func prepareConfig(parseOpts *cliOptions, conf *ffuf.Config) error {
errs.Add(fmt.Errorf("Header defined by -H needs to have a value. \":\" should be used as a separator"))
}
}
//Prepare delay
d := strings.Split(parseOpts.delay, "-")
if len(d) > 2 {
errs.Add(fmt.Errorf("Delay needs to be either a single float: \"0.1\" or a range of floats, delimited by dash: \"0.1-0.8\""))
} else if len(d) == 2 {
conf.Delay.IsRange = true
conf.Delay.HasDelay = true
conf.Delay.Min, err = strconv.ParseFloat(d[0], 64)
conf.Delay.Max, err2 = strconv.ParseFloat(d[1], 64)
if err != nil || err2 != nil {
errs.Add(fmt.Errorf("Delay range min and max values need to be valid floats. For example: 0.1-0.5"))
}
} else if len(parseOpts.delay) > 0 {
conf.Delay.IsRange = false
conf.Delay.HasDelay = true
conf.Delay.Min, err = strconv.ParseFloat(parseOpts.delay, 64)
if err != nil {
errs.Add(fmt.Errorf("Delay needs to be either a single float: \"0.1\" or a range of floats, delimited by dash: \"0.1-0.8\""))
}
}
//Search for keyword from URL and POST data too
if strings.Index(conf.Url, "FUZZ") != -1 {
foundkeyword = true

View file

@ -4,6 +4,15 @@ import (
"context"
)
//optRange stores either a single float, in which case the value is stored in min and IsRange is false,
//or a range of floats, in which case IsRange is true
type optRange struct {
Min float64
Max float64
IsRange bool
HasDelay bool
}
type Config struct {
StaticHeaders map[string]string
FuzzHeaders map[string]string
@ -14,6 +23,7 @@ type Config struct {
Quiet bool
Colors bool
Wordlist string
Delay optRange
Filters []FilterProvider
Matchers []FilterProvider
Threads int
@ -31,5 +41,6 @@ func NewConfig(ctx context.Context) Config {
conf.Data = ""
conf.Quiet = false
conf.Filters = make([]FilterProvider, 0)
conf.Delay = optRange{0, 0, false, false}
return conf
}

View file

@ -2,6 +2,7 @@ package ffuf
import (
"fmt"
"math/rand"
"sync"
"time"
)
@ -27,6 +28,7 @@ func NewJob(conf *Config) Job {
//Start the execution of the Job
func (j *Job) Start() {
rand.Seed(time.Now().UnixNano())
j.Total = j.Input.Total()
defer j.Stop()
//Show banner if not running in silent mode
@ -48,6 +50,16 @@ func (j *Job) Start() {
defer func() { <-limiter }()
defer wg.Done()
j.runTask([]byte(nextInput))
if j.Config.Delay.HasDelay {
var sleepDurationMS time.Duration
if j.Config.Delay.IsRange {
sTime := j.Config.Delay.Min + rand.Float64()*(j.Config.Delay.Max-j.Config.Delay.Min)
sleepDurationMS = time.Duration(sTime * 1000)
} else {
sleepDurationMS = time.Duration(j.Config.Delay.Min * 1000)
}
time.Sleep(sleepDurationMS * time.Millisecond)
}
}()
}
wg.Wait()