Replay matches using a chosen proxy (#140)
* Replay matches using a custom proxy * Add changelog entry
This commit is contained in:
parent
3d8e233097
commit
b0a632e6cd
@ -7,6 +7,7 @@
|
|||||||
- New CLI flag `-od` (output directory) to enable writing requests and responses for matched results to a file for postprocessing or debugging purposes.
|
- New CLI flag `-od` (output directory) to enable writing requests and responses for matched results to a file for postprocessing or debugging purposes.
|
||||||
- New CLI flag `-maxtime` to limit the running time of ffuf
|
- New CLI flag `-maxtime` to limit the running time of ffuf
|
||||||
- New CLI flags `-recursion` and `-recursion-depth` to control recursive ffuf jobs if directories are found. This requires the `-u` to end with FUZZ keyword.
|
- New CLI flags `-recursion` and `-recursion-depth` to control recursive ffuf jobs if directories are found. This requires the `-u` to end with FUZZ keyword.
|
||||||
|
- New CLI flag `-replay-proxy` to replay matched requests using a custom proxy.
|
||||||
- Changed
|
- Changed
|
||||||
- Limit the use of `-e` (extensions) to a single keyword: FUZZ
|
- Limit the use of `-e` (extensions) to a single keyword: FUZZ
|
||||||
- Regexp matching and filtering (-mr/-fr) allow using keywords in patterns
|
- Regexp matching and filtering (-mr/-fr) allow using keywords in patterns
|
||||||
|
|||||||
30
main.go
30
main.go
@ -33,6 +33,7 @@ type cliOptions struct {
|
|||||||
matcherWords string
|
matcherWords string
|
||||||
matcherLines string
|
matcherLines string
|
||||||
proxyURL string
|
proxyURL string
|
||||||
|
replayProxyURL string
|
||||||
request string
|
request string
|
||||||
requestProto string
|
requestProto string
|
||||||
outputFormat string
|
outputFormat string
|
||||||
@ -106,6 +107,7 @@ func main() {
|
|||||||
flag.BoolVar(&conf.FollowRedirects, "r", false, "Follow redirects")
|
flag.BoolVar(&conf.FollowRedirects, "r", false, "Follow redirects")
|
||||||
flag.BoolVar(&conf.Recursion, "recursion", false, "Scan recursively. Only FUZZ keyword is supported, and URL (-u) has to end in it.")
|
flag.BoolVar(&conf.Recursion, "recursion", false, "Scan recursively. Only FUZZ keyword is supported, and URL (-u) has to end in it.")
|
||||||
flag.IntVar(&conf.RecursionDepth, "recursion-depth", 0, "Maximum recursion depth.")
|
flag.IntVar(&conf.RecursionDepth, "recursion-depth", 0, "Maximum recursion depth.")
|
||||||
|
flag.StringVar(&opts.replayProxyURL, "replay-proxy", "", "Replay matched requests using this proxy.")
|
||||||
flag.BoolVar(&conf.AutoCalibration, "ac", false, "Automatically calibrate filtering options")
|
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")
|
flag.Var(&opts.AutoCalibrationStrings, "acc", "Custom auto-calibration string. Can be used multiple times. Implies -ac")
|
||||||
flag.IntVar(&conf.Threads, "t", 40, "Number of concurrent threads.")
|
flag.IntVar(&conf.Threads, "t", 40, "Number of concurrent threads.")
|
||||||
@ -158,6 +160,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func prepareJob(conf *ffuf.Config) (*ffuf.Job, error) {
|
func prepareJob(conf *ffuf.Config) (*ffuf.Job, error) {
|
||||||
|
job := &ffuf.Job{
|
||||||
|
Config: conf,
|
||||||
|
}
|
||||||
errs := ffuf.NewMultierror()
|
errs := ffuf.NewMultierror()
|
||||||
var err error
|
var err error
|
||||||
inputprovider, err := input.NewInputProvider(conf)
|
inputprovider, err := input.NewInputProvider(conf)
|
||||||
@ -166,7 +171,10 @@ func prepareJob(conf *ffuf.Config) (*ffuf.Job, error) {
|
|||||||
}
|
}
|
||||||
// TODO: implement error handling for runnerprovider and outputprovider
|
// TODO: implement error handling for runnerprovider and outputprovider
|
||||||
// We only have http runner right now
|
// We only have http runner right now
|
||||||
runprovider := runner.NewRunnerByName("http", conf)
|
job.Runner = runner.NewRunnerByName("http", conf, false)
|
||||||
|
if len(conf.ReplayProxyURL) > 0 {
|
||||||
|
job.ReplayRunner = runner.NewRunnerByName("http", conf, true)
|
||||||
|
}
|
||||||
// Initialize the correct inputprovider
|
// Initialize the correct inputprovider
|
||||||
for _, v := range conf.InputProviders {
|
for _, v := range conf.InputProviders {
|
||||||
err = inputprovider.AddProvider(v)
|
err = inputprovider.AddProvider(v)
|
||||||
@ -174,14 +182,10 @@ func prepareJob(conf *ffuf.Config) (*ffuf.Job, error) {
|
|||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
job.Input = inputprovider
|
||||||
// We only have stdout outputprovider right now
|
// We only have stdout outputprovider right now
|
||||||
outprovider := output.NewOutputProviderByName("stdout", conf)
|
job.Output = output.NewOutputProviderByName("stdout", conf)
|
||||||
return &ffuf.Job{
|
return job, errs.ErrorOrNil()
|
||||||
Config: conf,
|
|
||||||
Runner: runprovider,
|
|
||||||
Output: outprovider,
|
|
||||||
Input: inputprovider,
|
|
||||||
}, errs.ErrorOrNil()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareFilters(parseOpts *cliOptions, conf *ffuf.Config) error {
|
func prepareFilters(parseOpts *cliOptions, conf *ffuf.Config) error {
|
||||||
@ -349,6 +353,16 @@ func prepareConfig(parseOpts *cliOptions, conf *ffuf.Config) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify replayproxy url format
|
||||||
|
if len(parseOpts.replayProxyURL) > 0 {
|
||||||
|
_, err := url.Parse(parseOpts.replayProxyURL)
|
||||||
|
if err != nil {
|
||||||
|
errs.Add(fmt.Errorf("Bad replay-proxy url (-replay-proxy) format: %s", err))
|
||||||
|
} else {
|
||||||
|
conf.ReplayProxyURL = parseOpts.replayProxyURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Check the output file format option
|
//Check the output file format option
|
||||||
if conf.OutputFile != "" {
|
if conf.OutputFile != "" {
|
||||||
//No need to check / error out if output file isn't defined
|
//No need to check / error out if output file isn't defined
|
||||||
|
|||||||
@ -35,6 +35,7 @@ type Config struct {
|
|||||||
Threads int `json:"threads"`
|
Threads int `json:"threads"`
|
||||||
Context context.Context `json:"-"`
|
Context context.Context `json:"-"`
|
||||||
ProxyURL string `json:"proxyurl"`
|
ProxyURL string `json:"proxyurl"`
|
||||||
|
ReplayProxyURL string `json:"replayproxyurl"`
|
||||||
CommandLine string `json:"cmdline"`
|
CommandLine string `json:"cmdline"`
|
||||||
Verbose bool `json:"verbose"`
|
Verbose bool `json:"verbose"`
|
||||||
MaxTime int `json:"maxtime"`
|
MaxTime int `json:"maxtime"`
|
||||||
|
|||||||
@ -17,6 +17,7 @@ type Job struct {
|
|||||||
ErrorMutex sync.Mutex
|
ErrorMutex sync.Mutex
|
||||||
Input InputProvider
|
Input InputProvider
|
||||||
Runner RunnerProvider
|
Runner RunnerProvider
|
||||||
|
ReplayRunner RunnerProvider
|
||||||
Output OutputProvider
|
Output OutputProvider
|
||||||
Counter int
|
Counter int
|
||||||
ErrorCounter int
|
ErrorCounter int
|
||||||
@ -261,6 +262,18 @@ func (j *Job) runTask(input map[string][]byte, position int, retried bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if j.isMatch(resp) {
|
if j.isMatch(resp) {
|
||||||
|
// Re-send request through replay-proxy if needed
|
||||||
|
if j.ReplayRunner != nil {
|
||||||
|
replayreq, err := j.ReplayRunner.Prepare(input)
|
||||||
|
replayreq.Position = position
|
||||||
|
if err != nil {
|
||||||
|
j.Output.Error(fmt.Sprintf("Encountered an error while preparing replayproxy request: %s\n", err))
|
||||||
|
j.incError()
|
||||||
|
log.Printf("%s", err)
|
||||||
|
} else {
|
||||||
|
_, _ = j.ReplayRunner.Execute(&replayreq)
|
||||||
|
}
|
||||||
|
}
|
||||||
j.Output.Result(resp)
|
j.Output.Result(resp)
|
||||||
// Refresh the progress indicator as we printed something out
|
// Refresh the progress indicator as we printed something out
|
||||||
j.updateProgress()
|
j.updateProgress()
|
||||||
|
|||||||
@ -87,6 +87,16 @@ func (s *Stdoutput) Banner() error {
|
|||||||
autocalib := fmt.Sprintf("%t", s.config.AutoCalibration)
|
autocalib := fmt.Sprintf("%t", s.config.AutoCalibration)
|
||||||
printOption([]byte("Calibration"), []byte(autocalib))
|
printOption([]byte("Calibration"), []byte(autocalib))
|
||||||
|
|
||||||
|
// Proxies
|
||||||
|
if len(s.config.ProxyURL) > 0 {
|
||||||
|
proxy := fmt.Sprintf("%s", s.config.ProxyURL)
|
||||||
|
printOption([]byte("Proxy"), []byte(proxy))
|
||||||
|
}
|
||||||
|
if len(s.config.ReplayProxyURL) > 0 {
|
||||||
|
replayproxy := fmt.Sprintf("%s", s.config.ReplayProxyURL)
|
||||||
|
printOption([]byte("ReplayProxy"), []byte(replayproxy))
|
||||||
|
}
|
||||||
|
|
||||||
// Timeout
|
// Timeout
|
||||||
timeout := fmt.Sprintf("%d", s.config.Timeout)
|
timeout := fmt.Sprintf("%d", s.config.Timeout)
|
||||||
printOption([]byte("Timeout"), []byte(timeout))
|
printOption([]byte("Timeout"), []byte(timeout))
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/ffuf/ffuf/pkg/ffuf"
|
"github.com/ffuf/ffuf/pkg/ffuf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewRunnerByName(name string, conf *ffuf.Config) ffuf.RunnerProvider {
|
func NewRunnerByName(name string, conf *ffuf.Config, replay bool) ffuf.RunnerProvider {
|
||||||
// We have only one Runner at the moment
|
// We have only one Runner at the moment
|
||||||
return NewSimpleRunner(conf)
|
return NewSimpleRunner(conf, replay)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,12 +23,18 @@ type SimpleRunner struct {
|
|||||||
client *http.Client
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSimpleRunner(conf *ffuf.Config) ffuf.RunnerProvider {
|
func NewSimpleRunner(conf *ffuf.Config, replay bool) ffuf.RunnerProvider {
|
||||||
var simplerunner SimpleRunner
|
var simplerunner SimpleRunner
|
||||||
proxyURL := http.ProxyFromEnvironment
|
proxyURL := http.ProxyFromEnvironment
|
||||||
|
customProxy := ""
|
||||||
|
|
||||||
if len(conf.ProxyURL) > 0 {
|
if replay {
|
||||||
pu, err := url.Parse(conf.ProxyURL)
|
customProxy = conf.ReplayProxyURL
|
||||||
|
} else {
|
||||||
|
customProxy = conf.ProxyURL
|
||||||
|
}
|
||||||
|
if len(customProxy) > 0 {
|
||||||
|
pu, err := url.Parse(customProxy)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
proxyURL = http.ProxyURL(pu)
|
proxyURL = http.ProxyURL(pu)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user