mirror of
https://github.com/ffuf/ffuf
synced 2024-11-10 06:04:17 +00:00
Choose between 'and' and 'or' matching and filtering (#20)
This commit is contained in:
parent
9fa0a5d20a
commit
21a19a1f3d
7 changed files with 57 additions and 4 deletions
|
@ -1,6 +1,8 @@
|
|||
## Changelog
|
||||
- master
|
||||
- New
|
||||
- New autocalibration options: `-ach`, `-ack` and `-acs`. Revamped the whole autocalibration process
|
||||
- Configurable modes for matchers and filters (CLI flags: `fmode` and `mmode`): "and" and "or"
|
||||
- Changed
|
||||
|
||||
- v1.4.1
|
||||
|
@ -16,7 +18,6 @@
|
|||
- Added full line colors
|
||||
- Added `-json` to emit newline delimited JSON output
|
||||
- Added 500 Internal Server Error to list of status codes matched by default
|
||||
- New autocalibration options: `-ach`, `-ack` and `-acs`. Revamped the whole autocalibration process
|
||||
- Changed
|
||||
- Fixed an issue where output file was created regardless of `-or`
|
||||
- Fixed an issue where output (often a lot of it) would be printed after entering interactive mode
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
outputcreateemptyfile = false
|
||||
|
||||
[filter]
|
||||
mode = "or"
|
||||
lines = ""
|
||||
regexp = ""
|
||||
size = ""
|
||||
|
@ -77,6 +78,7 @@
|
|||
words = ""
|
||||
|
||||
[matcher]
|
||||
mode = "or"
|
||||
lines = ""
|
||||
regexp = ""
|
||||
size = ""
|
||||
|
|
4
help.go
4
help.go
|
@ -75,14 +75,14 @@ func Usage() {
|
|||
Description: "Matchers for the response filtering.",
|
||||
Flags: make([]UsageFlag, 0),
|
||||
Hidden: false,
|
||||
ExpectedFlags: []string{"mc", "ml", "mr", "ms", "mt", "mw"},
|
||||
ExpectedFlags: []string{"mmode", "mc", "ml", "mr", "ms", "mt", "mw"},
|
||||
}
|
||||
u_filter := UsageSection{
|
||||
Name: "FILTER OPTIONS",
|
||||
Description: "Filters for the response filtering.",
|
||||
Flags: make([]UsageFlag, 0),
|
||||
Hidden: false,
|
||||
ExpectedFlags: []string{"fc", "fl", "fr", "fs", "ft", "fw"},
|
||||
ExpectedFlags: []string{"fmode", "fc", "fl", "fr", "fs", "ft", "fw"},
|
||||
}
|
||||
u_input := UsageSection{
|
||||
Name: "INPUT OPTIONS",
|
||||
|
|
2
main.go
2
main.go
|
@ -88,6 +88,7 @@ func ParseFlags(opts *ffuf.ConfigOptions) *ffuf.ConfigOptions {
|
|||
flag.StringVar(&opts.General.AutoCalibrationKeyword, "ack", opts.General.AutoCalibrationKeyword, "Autocalibration keyword")
|
||||
flag.StringVar(&opts.General.AutoCalibrationStrategy, "acs", opts.General.AutoCalibrationStrategy, "Autocalibration strategy: \"basic\" or \"advanced\"")
|
||||
flag.StringVar(&opts.General.ConfigFile, "config", "", "Load configuration from a file")
|
||||
flag.StringVar(&opts.Filter.Mode, "fmode", opts.Filter.Mode, "Filter set operator. Either of: and, or")
|
||||
flag.StringVar(&opts.Filter.Lines, "fl", opts.Filter.Lines, "Filter by amount of lines in response. Comma separated list of line counts and ranges")
|
||||
flag.StringVar(&opts.Filter.Regexp, "fr", opts.Filter.Regexp, "Filter regexp")
|
||||
flag.StringVar(&opts.Filter.Size, "fs", opts.Filter.Size, "Filter HTTP response size. Comma separated list of sizes and ranges")
|
||||
|
@ -110,6 +111,7 @@ func ParseFlags(opts *ffuf.ConfigOptions) *ffuf.ConfigOptions {
|
|||
flag.StringVar(&opts.Input.InputShell, "input-shell", opts.Input.InputShell, "Shell to be used for running command")
|
||||
flag.StringVar(&opts.Input.Request, "request", opts.Input.Request, "File containing the raw http request")
|
||||
flag.StringVar(&opts.Input.RequestProto, "request-proto", opts.Input.RequestProto, "Protocol to use along with raw request")
|
||||
flag.StringVar(&opts.Matcher.Mode, "mmode", opts.Matcher.Mode, "Matcher set operator. Either of: and, or")
|
||||
flag.StringVar(&opts.Matcher.Lines, "ml", opts.Matcher.Lines, "Match amount of lines in response")
|
||||
flag.StringVar(&opts.Matcher.Regexp, "mr", opts.Matcher.Regexp, "Match regexp")
|
||||
flag.StringVar(&opts.Matcher.Size, "ms", opts.Matcher.Size, "Match HTTP response size")
|
||||
|
|
|
@ -20,6 +20,7 @@ type Config struct {
|
|||
Delay optRange `json:"delay"`
|
||||
DirSearchCompat bool `json:"dirsearch_compatibility"`
|
||||
Extensions []string `json:"extensions"`
|
||||
FilterMode string `json:"fmode"`
|
||||
FollowRedirects bool `json:"follow_redirects"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
IgnoreBody bool `json:"ignorebody"`
|
||||
|
@ -30,6 +31,7 @@ type Config struct {
|
|||
InputShell string `json:"inputshell"`
|
||||
Json bool `json:"json"`
|
||||
MatcherManager MatcherManager `json:"matchers"`
|
||||
MatcherMode string `json:"mmode"`
|
||||
MaxTime int `json:"maxtime"`
|
||||
MaxTimeJob int `json:"maxtime_job"`
|
||||
Method string `json:"method"`
|
||||
|
@ -76,6 +78,7 @@ func NewConfig(ctx context.Context, cancel context.CancelFunc) Config {
|
|||
conf.Delay = optRange{0, 0, false, false}
|
||||
conf.DirSearchCompat = false
|
||||
conf.Extensions = make([]string, 0)
|
||||
conf.FilterMode = "or"
|
||||
conf.FollowRedirects = false
|
||||
conf.Headers = make(map[string]string)
|
||||
conf.IgnoreWordlistComments = false
|
||||
|
@ -84,6 +87,7 @@ func NewConfig(ctx context.Context, cancel context.CancelFunc) Config {
|
|||
conf.InputShell = ""
|
||||
conf.InputProviders = make([]InputProviderConfig, 0)
|
||||
conf.Json = false
|
||||
conf.MatcherMode = "or"
|
||||
conf.MaxTime = 0
|
||||
conf.MaxTimeJob = 0
|
||||
conf.Method = "GET"
|
||||
|
|
|
@ -341,6 +341,10 @@ func (j *Job) isMatch(resp Response) bool {
|
|||
}
|
||||
if match {
|
||||
matched = true
|
||||
} else if j.Config.MatcherMode == "and" {
|
||||
// we already know this isn't "and" match
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
// The response was not matched, return before running filters
|
||||
|
@ -353,8 +357,21 @@ func (j *Job) isMatch(resp Response) bool {
|
|||
continue
|
||||
}
|
||||
if fv {
|
||||
// return false
|
||||
if j.Config.FilterMode == "or" {
|
||||
// return early, as filter matched
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if j.Config.FilterMode == "and" {
|
||||
// return early as not all filters matched in "and" mode
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(filters) > 0 && j.Config.FilterMode == "and" {
|
||||
// we did not return early, so all filters were matched
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ type OutputOptions struct {
|
|||
}
|
||||
|
||||
type FilterOptions struct {
|
||||
Mode string
|
||||
Lines string
|
||||
Regexp string
|
||||
Size string
|
||||
|
@ -97,6 +98,7 @@ type FilterOptions struct {
|
|||
}
|
||||
|
||||
type MatcherOptions struct {
|
||||
Mode string
|
||||
Lines string
|
||||
Regexp string
|
||||
Size string
|
||||
|
@ -108,6 +110,7 @@ type MatcherOptions struct {
|
|||
//NewConfigOptions returns a newly created ConfigOptions struct with default values
|
||||
func NewConfigOptions() *ConfigOptions {
|
||||
c := &ConfigOptions{}
|
||||
c.Filter.Mode = "or"
|
||||
c.Filter.Lines = ""
|
||||
c.Filter.Regexp = ""
|
||||
c.Filter.Size = ""
|
||||
|
@ -151,6 +154,7 @@ func NewConfigOptions() *ConfigOptions {
|
|||
c.Input.InputNum = 100
|
||||
c.Input.Request = ""
|
||||
c.Input.RequestProto = "https"
|
||||
c.Matcher.Mode = "or"
|
||||
c.Matcher.Lines = ""
|
||||
c.Matcher.Regexp = ""
|
||||
c.Matcher.Size = ""
|
||||
|
@ -461,6 +465,29 @@ func ConfigFromOptions(parseOpts *ConfigOptions, ctx context.Context, cancel con
|
|||
conf.Json = parseOpts.General.Json
|
||||
conf.Http2 = parseOpts.HTTP.Http2
|
||||
|
||||
// Check that fmode and mmode have sane values
|
||||
valid_opmodes := []string{"and", "or"}
|
||||
fmode_found := false
|
||||
mmode_found := false
|
||||
for _, v := range valid_opmodes {
|
||||
if v == parseOpts.Filter.Mode {
|
||||
fmode_found = true
|
||||
}
|
||||
if v == parseOpts.Matcher.Mode {
|
||||
mmode_found = true
|
||||
}
|
||||
}
|
||||
if !fmode_found {
|
||||
errmsg := fmt.Sprintf("Unrecognized value for parameter fmode: %s, valid values are: and, or", parseOpts.Filter.Mode)
|
||||
errs.Add(fmt.Errorf(errmsg))
|
||||
}
|
||||
if !mmode_found {
|
||||
errmsg := fmt.Sprintf("Unrecognized value for parameter mmode: %s, valid values are: and, or", parseOpts.Matcher.Mode)
|
||||
errs.Add(fmt.Errorf(errmsg))
|
||||
}
|
||||
conf.FilterMode = parseOpts.Filter.Mode
|
||||
conf.MatcherMode = parseOpts.Matcher.Mode
|
||||
|
||||
if conf.AutoCalibrationPerHost {
|
||||
// AutoCalibrationPerHost implies AutoCalibration
|
||||
conf.AutoCalibration = true
|
||||
|
|
Loading…
Reference in a new issue