Support outputting all file formats concurrently (#218)

* Support outputting all file formats concurrently

Previously ffuf would allow outputting to a single
file-format, ie Markdown (md), json or HTML.  It was not
possible to output in multiple formats in the same
execution.

This change allows specifying an output (-of) of "all",
which means that the output filename (-o) is used, but the
appropriate suffix is added.

As an example,
... -of all -o output/report

Will output:
 - output/report.json
 - output/report.html
 - output/report.csv
 - ... etc

Fixes ffuf/ffuf#215

Signed-off-by: Dave Walker (Daviey) <email@daviey.com>

* Updated Changelog and added myself to CONTRIBUTORS

Signed-off-by: Dave Walker (Daviey) <email@daviey.com>

* Fix file extension for 'ecsv' when 'all' is used

.. And fix CONTRIBUTORS.md to be alphabetical

Signed-off-by: Dave Walker (Daviey) <email@daviey.com>
This commit is contained in:
Dave Walker 2020-04-19 10:11:15 +01:00 committed by GitHub
parent e4628ff481
commit 88720dfdc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 4 deletions

View file

@ -6,6 +6,7 @@
- Changed behaviour of `-maxtime`, can now be used for entire process.
- A new flag `-ignore-body` so ffuf does not fetch the response content. Default value=false.
- Added the wordlists to the header information.
- Added support to output "all" formats (specify the path/filename sans file extension and ffuf will add the appropriate suffix for the filetype)
- Changed
- Added tls renegotiation flag to fix #193 in http.Client

View file

@ -101,7 +101,7 @@ func main() {
flag.StringVar(&opts.requestProto, "request-proto", "https", "Protocol to use along with raw request")
flag.StringVar(&conf.Method, "X", "GET", "HTTP method to use")
flag.StringVar(&conf.OutputFile, "o", "", "Write output to file")
flag.StringVar(&opts.outputFormat, "of", "json", "Output file format. Available formats: json, ejson, html, md, csv, ecsv")
flag.StringVar(&opts.outputFormat, "of", "json", "Output file format. Available formats: json, ejson, html, md, csv, ecsv (or, 'all' for all formats)")
flag.StringVar(&conf.OutputDirectory, "od", "", "Directory path to store matched results to.")
flag.BoolVar(&conf.IgnoreBody, "ignore-body", false, "Do not fetch the response content.")
flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)")
@ -430,7 +430,7 @@ func prepareConfig(parseOpts *cliOptions, conf *ffuf.Config) error {
//Check the output file format option
if conf.OutputFile != "" {
//No need to check / error out if output file isn't defined
outputFormats := []string{"json", "ejson", "html", "md", "csv", "ecsv"}
outputFormats := []string{"all", "json", "ejson", "html", "md", "csv", "ecsv"}
found := false
for _, f := range outputFormats {
if f == parseOpts.outputFormat {

View file

@ -83,7 +83,16 @@ func (s *Stdoutput) Banner() error {
// Output file info
if len(s.config.OutputFile) > 0 {
printOption([]byte("Output file"), []byte(s.config.OutputFile))
// Use filename as specified by user
OutputFile := s.config.OutputFile
if s.config.OutputFormat == "all" {
// Actually... append all extensions
OutputFile += ".{json,ejson,html,md,csv,ecsv}"
}
printOption([]byte("Output file"), []byte(OutputFile))
printOption([]byte("File format"), []byte(s.config.OutputFormat))
}
@ -196,10 +205,59 @@ func (s *Stdoutput) Warning(warnstring string) {
}
}
func (s *Stdoutput) writeToAll(config *ffuf.Config, res []Result) error {
var err error
var BaseFilename string = s.config.OutputFile
// Go through each type of write, adding
// the suffix to each output file.
s.config.OutputFile = BaseFilename + ".json"
err = writeJSON(s.config, s.Results)
if err != nil {
s.Error(fmt.Sprintf("%s", err))
}
s.config.OutputFile = BaseFilename + ".ejson"
err = writeEJSON(s.config, s.Results)
if err != nil {
s.Error(fmt.Sprintf("%s", err))
}
s.config.OutputFile = BaseFilename + ".html"
err = writeHTML(s.config, s.Results)
if err != nil {
s.Error(fmt.Sprintf("%s", err))
}
s.config.OutputFile = BaseFilename + ".md"
err = writeMarkdown(s.config, s.Results)
if err != nil {
s.Error(fmt.Sprintf("%s", err))
}
s.config.OutputFile = BaseFilename + ".csv"
err = writeCSV(s.config, s.Results, false)
if err != nil {
s.Error(fmt.Sprintf("%s", err))
}
s.config.OutputFile = BaseFilename + ".ecsv"
err = writeCSV(s.config, s.Results, true)
if err != nil {
s.Error(fmt.Sprintf("%s", err))
}
return nil
}
func (s *Stdoutput) Finalize() error {
var err error
if s.config.OutputFile != "" {
if s.config.OutputFormat == "json" {
if s.config.OutputFormat == "all" {
err = s.writeToAll(s.config, s.Results)
} else if s.config.OutputFormat == "json" {
err = writeJSON(s.config, s.Results)
} else if s.config.OutputFormat == "ejson" {
err = writeEJSON(s.config, s.Results)