Empty filter (#330)
* add support to filter empty result files. * update readme * add contributors. * add changelog * Update ffufrc.example
This commit is contained in:
parent
c6a6293499
commit
bc5e61ecc3
@ -6,6 +6,7 @@
|
|||||||
- Ffuf now reads a default configuration file `$HOME/.ffufrc` upon startup. Options set in this file
|
- Ffuf now reads a default configuration file `$HOME/.ffufrc` upon startup. Options set in this file
|
||||||
are overwritten by the ones provided on CLI.
|
are overwritten by the ones provided on CLI.
|
||||||
- Change banner logging to stderr instead of stdout.
|
- Change banner logging to stderr instead of stdout.
|
||||||
|
- New CLI flag `-or` to avoid creating result files if we didn't get any.
|
||||||
|
|
||||||
- Changed
|
- Changed
|
||||||
- Pre-flight errors are now displayed also after the usage text to prevent the need to scroll through backlog.
|
- Pre-flight errors are now displayed also after the usage text to prevent the need to scroll through backlog.
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
# Contributors
|
# Contributors
|
||||||
* [AverageSecurityGuy](https://github.com/averagesecurityguy)
|
* [AverageSecurityGuy](https://github.com/averagesecurityguy)
|
||||||
|
* [bp0](https://github.com/bp0lr)
|
||||||
* [bjhulst](https://github.com/bjhulst)
|
* [bjhulst](https://github.com/bjhulst)
|
||||||
* [bsysop](https://twitter.com/bsysop)
|
* [bsysop](https://twitter.com/bsysop)
|
||||||
* [ccsplit](https://github.com/ccsplit)
|
* [ccsplit](https://github.com/ccsplit)
|
||||||
|
|||||||
@ -195,6 +195,7 @@ OUTPUT OPTIONS:
|
|||||||
-o Write output to file
|
-o Write output to file
|
||||||
-od Directory path to store matched results to.
|
-od Directory path to store matched results to.
|
||||||
-of Output file format. Available formats: json, ejson, html, md, csv, ecsv (or, 'all' for all formats) (default: json)
|
-of Output file format. Available formats: json, ejson, html, md, csv, ecsv (or, 'all' for all formats) (default: json)
|
||||||
|
-or Don't create the output file if we don't have results
|
||||||
|
|
||||||
EXAMPLE USAGE:
|
EXAMPLE USAGE:
|
||||||
Fuzz file paths from wordlist.txt, match all responses but filter out those with content-size 42.
|
Fuzz file paths from wordlist.txt, match all responses but filter out those with content-size 42.
|
||||||
|
|||||||
@ -60,6 +60,7 @@
|
|||||||
outputdirectory = "/tmp/rawoutputdir"
|
outputdirectory = "/tmp/rawoutputdir"
|
||||||
outputfile = "output.json"
|
outputfile = "output.json"
|
||||||
outputformat = "json"
|
outputformat = "json"
|
||||||
|
outputcreateemptyfile = false
|
||||||
|
|
||||||
[filter]
|
[filter]
|
||||||
lines = ""
|
lines = ""
|
||||||
|
|||||||
2
help.go
2
help.go
@ -96,7 +96,7 @@ func Usage() {
|
|||||||
Description: "Options for output. Output file formats, file names and debug file locations.",
|
Description: "Options for output. Output file formats, file names and debug file locations.",
|
||||||
Flags: make([]UsageFlag, 0),
|
Flags: make([]UsageFlag, 0),
|
||||||
Hidden: false,
|
Hidden: false,
|
||||||
ExpectedFlags: []string{"debug-log", "o", "of", "od"},
|
ExpectedFlags: []string{"debug-log", "o", "of", "od", "or"},
|
||||||
}
|
}
|
||||||
sections := []UsageSection{u_http, u_general, u_compat, u_matcher, u_filter, u_input, u_output}
|
sections := []UsageSection{u_http, u_general, u_compat, u_matcher, u_filter, u_input, u_output}
|
||||||
|
|
||||||
|
|||||||
1
main.go
1
main.go
@ -58,6 +58,7 @@ func ParseFlags(opts *ffuf.ConfigOptions) *ffuf.ConfigOptions {
|
|||||||
flag.BoolVar(&ignored, "compressed", true, "Dummy flag for copy as curl functionality (ignored)")
|
flag.BoolVar(&ignored, "compressed", true, "Dummy flag for copy as curl functionality (ignored)")
|
||||||
flag.BoolVar(&ignored, "i", true, "Dummy flag for copy as curl functionality (ignored)")
|
flag.BoolVar(&ignored, "i", true, "Dummy flag for copy as curl functionality (ignored)")
|
||||||
flag.BoolVar(&ignored, "k", false, "Dummy flag for backwards compatibility")
|
flag.BoolVar(&ignored, "k", false, "Dummy flag for backwards compatibility")
|
||||||
|
flag.BoolVar(&opts.Output.OutputCreateEmptyFile, "or", opts.Output.OutputCreateEmptyFile, "Don't create the output file if we don't have results")
|
||||||
flag.BoolVar(&opts.General.AutoCalibration, "ac", opts.General.AutoCalibration, "Automatically calibrate filtering options")
|
flag.BoolVar(&opts.General.AutoCalibration, "ac", opts.General.AutoCalibration, "Automatically calibrate filtering options")
|
||||||
flag.BoolVar(&opts.General.Colors, "c", opts.General.Colors, "Colorize output.")
|
flag.BoolVar(&opts.General.Colors, "c", opts.General.Colors, "Colorize output.")
|
||||||
flag.BoolVar(&opts.General.Quiet, "s", opts.General.Quiet, "Do not print additional information (silent mode)")
|
flag.BoolVar(&opts.General.Quiet, "s", opts.General.Quiet, "Do not print additional information (silent mode)")
|
||||||
|
|||||||
@ -32,6 +32,7 @@ type Config struct {
|
|||||||
OutputDirectory string `json:"outputdirectory"`
|
OutputDirectory string `json:"outputdirectory"`
|
||||||
OutputFile string `json:"outputfile"`
|
OutputFile string `json:"outputfile"`
|
||||||
OutputFormat string `json:"outputformat"`
|
OutputFormat string `json:"outputformat"`
|
||||||
|
OutputCreateEmptyFile bool `json:"OutputCreateEmptyFile"`
|
||||||
ProgressFrequency int `json:"-"`
|
ProgressFrequency int `json:"-"`
|
||||||
ProxyURL string `json:"proxyurl"`
|
ProxyURL string `json:"proxyurl"`
|
||||||
Quiet bool `json:"quiet"`
|
Quiet bool `json:"quiet"`
|
||||||
|
|||||||
@ -75,6 +75,7 @@ type OutputOptions struct {
|
|||||||
OutputDirectory string
|
OutputDirectory string
|
||||||
OutputFile string
|
OutputFile string
|
||||||
OutputFormat string
|
OutputFormat string
|
||||||
|
OutputCreateEmptyFile bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type FilterOptions struct {
|
type FilterOptions struct {
|
||||||
@ -140,6 +141,7 @@ func NewConfigOptions() *ConfigOptions {
|
|||||||
c.Output.OutputDirectory = ""
|
c.Output.OutputDirectory = ""
|
||||||
c.Output.OutputFile = ""
|
c.Output.OutputFile = ""
|
||||||
c.Output.OutputFormat = "json"
|
c.Output.OutputFormat = "json"
|
||||||
|
c.Output.OutputCreateEmptyFile = false
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,6 +376,7 @@ func ConfigFromOptions(parseOpts *ConfigOptions, ctx context.Context, cancel con
|
|||||||
conf.InputMode = parseOpts.Input.InputMode
|
conf.InputMode = parseOpts.Input.InputMode
|
||||||
conf.OutputFile = parseOpts.Output.OutputFile
|
conf.OutputFile = parseOpts.Output.OutputFile
|
||||||
conf.OutputDirectory = parseOpts.Output.OutputDirectory
|
conf.OutputDirectory = parseOpts.Output.OutputDirectory
|
||||||
|
conf.OutputCreateEmptyFile = parseOpts.Output.OutputCreateEmptyFile
|
||||||
conf.IgnoreBody = parseOpts.HTTP.IgnoreBody
|
conf.IgnoreBody = parseOpts.HTTP.IgnoreBody
|
||||||
conf.Quiet = parseOpts.General.Quiet
|
conf.Quiet = parseOpts.General.Quiet
|
||||||
conf.StopOn403 = parseOpts.General.StopOn403
|
conf.StopOn403 = parseOpts.General.StopOn403
|
||||||
|
|||||||
@ -12,6 +12,11 @@ import (
|
|||||||
var staticheaders = []string{"url", "redirectlocation", "position", "status_code", "content_length", "content_words", "content_lines", "resultfile"}
|
var staticheaders = []string{"url", "redirectlocation", "position", "status_code", "content_length", "content_words", "content_lines", "resultfile"}
|
||||||
|
|
||||||
func writeCSV(config *ffuf.Config, res []Result, encode bool) error {
|
func writeCSV(config *ffuf.Config, res []Result, encode bool) error {
|
||||||
|
|
||||||
|
if(config.OutputCreateEmptyFile && (len(res) == 0)){
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
header := make([]string, 0)
|
header := make([]string, 0)
|
||||||
f, err := os.Create(config.OutputFile)
|
f, err := os.Create(config.OutputFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -176,6 +176,10 @@ func colorizeResults(results []Result) []Result {
|
|||||||
|
|
||||||
func writeHTML(config *ffuf.Config, results []Result) error {
|
func writeHTML(config *ffuf.Config, results []Result) error {
|
||||||
|
|
||||||
|
if(config.OutputCreateEmptyFile && (len(results) == 0)){
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
results = colorizeResults(results)
|
results = colorizeResults(results)
|
||||||
|
|
||||||
ti := time.Now()
|
ti := time.Now()
|
||||||
|
|||||||
@ -36,6 +36,11 @@ type jsonFileOutput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writeEJSON(config *ffuf.Config, res []Result) error {
|
func writeEJSON(config *ffuf.Config, res []Result) error {
|
||||||
|
|
||||||
|
if(config.OutputCreateEmptyFile && (len(res) == 0)){
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
outJSON := ejsonFileOutput{
|
outJSON := ejsonFileOutput{
|
||||||
CommandLine: config.CommandLine,
|
CommandLine: config.CommandLine,
|
||||||
|
|||||||
@ -22,6 +22,10 @@ const (
|
|||||||
|
|
||||||
func writeMarkdown(config *ffuf.Config, res []Result) error {
|
func writeMarkdown(config *ffuf.Config, res []Result) error {
|
||||||
|
|
||||||
|
if(config.OutputCreateEmptyFile && (len(res) == 0)){
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
ti := time.Now()
|
ti := time.Now()
|
||||||
|
|
||||||
keywords := make([]string, 0)
|
keywords := make([]string, 0)
|
||||||
|
|||||||
@ -210,6 +210,10 @@ func (s *Stdoutput) writeToAll(config *ffuf.Config, res []Result) error {
|
|||||||
// Go through each type of write, adding
|
// Go through each type of write, adding
|
||||||
// the suffix to each output file.
|
// the suffix to each output file.
|
||||||
|
|
||||||
|
if(config.OutputCreateEmptyFile && (len(res) == 0)){
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
s.config.OutputFile = BaseFilename + ".json"
|
s.config.OutputFile = BaseFilename + ".json"
|
||||||
err = writeJSON(s.config, s.Results)
|
err = writeJSON(s.config, s.Results)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user