Add output to CSV file (#12)

This commit is contained in:
Sebastian Lawniczak 2019-04-03 11:51:42 +02:00 committed by Joona Hoikkala
parent ab09685804
commit 9934cfdfc3
4 changed files with 58 additions and 3 deletions

View File

@ -99,7 +99,7 @@ To define the test case for ffuf, use the keyword `FUZZ` anywhere in the URL (`-
-o string -o string
Write output to file Write output to file
-of string -of string
Output file format. Available formats: json (default "json") Output file format. Available formats: json, csv, ecsv (default "json")
-p delay -p delay
Seconds of delay between requests, or a range of random delay. For example "0.1" or "0.1-2.0" 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) -s Do not print additional information (silent mode)

View File

@ -67,7 +67,7 @@ func main() {
flag.StringVar(&opts.proxyURL, "x", "", "HTTP Proxy URL") flag.StringVar(&opts.proxyURL, "x", "", "HTTP Proxy URL")
flag.StringVar(&conf.Method, "X", "GET", "HTTP method to use") flag.StringVar(&conf.Method, "X", "GET", "HTTP method to use")
flag.StringVar(&conf.OutputFile, "o", "", "Write output to file") flag.StringVar(&conf.OutputFile, "o", "", "Write output to file")
flag.StringVar(&opts.outputFormat, "of", "json", "Output file format. Available formats: json") flag.StringVar(&opts.outputFormat, "of", "json", "Output file format. Available formats: json, csv, ecsv")
flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)") flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)")
flag.BoolVar(&conf.StopOn403, "sf", false, "Stop when > 90% of responses return 403 Forbidden") flag.BoolVar(&conf.StopOn403, "sf", false, "Stop when > 90% of responses return 403 Forbidden")
flag.IntVar(&conf.Threads, "t", 40, "Number of concurrent threads.") flag.IntVar(&conf.Threads, "t", 40, "Number of concurrent threads.")
@ -186,7 +186,7 @@ func prepareConfig(parseOpts *cliOptions, conf *ffuf.Config) error {
//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
outputFormats := []string{"json"} outputFormats := []string{"json", "csv", "ecsv"}
found := false found := false
for _, f := range outputFormats { for _, f := range outputFormats {
if f == parseOpts.outputFormat { if f == parseOpts.outputFormat {

51
pkg/output/file_csv.go Normal file
View File

@ -0,0 +1,51 @@
package output
import (
"encoding/base64"
"encoding/csv"
"os"
"strconv"
"github.com/ffuf/ffuf/pkg/ffuf"
)
var header = []string{"input", "status_code", "content_length", "content_words"}
func writeCSV(config *ffuf.Config, res []Result, encode bool) error {
f, err := os.Create(config.OutputFile)
if err != nil {
return err
}
defer f.Close()
w := csv.NewWriter(f)
defer w.Flush()
if err := w.Write(header); err != nil {
return err
}
for _, r := range res {
if encode {
r.Input = base64encode(r.Input)
}
err := w.Write(toCSV(r))
if err != nil {
return err
}
}
return nil
}
func base64encode(in string) string {
return base64.StdEncoding.EncodeToString([]byte(in))
}
func toCSV(r Result) []string {
return []string{
r.Input,
strconv.FormatInt(r.StatusCode, 10),
strconv.FormatInt(r.ContentLength, 10),
strconv.FormatInt(r.ContentWords, 10),
}
}

View File

@ -90,6 +90,10 @@ func (s *Stdoutput) Finalize() error {
if s.config.OutputFile != "" { if s.config.OutputFile != "" {
if s.config.OutputFormat == "json" { if s.config.OutputFormat == "json" {
err = writeJSON(s.config, s.Results) err = writeJSON(s.config, s.Results)
} else if s.config.OutputFormat == "csv" {
err = writeCSV(s.config, s.Results, false)
} else if s.config.OutputFormat == "ecsv" {
err = writeCSV(s.config, s.Results, true)
} }
if err != nil { if err != nil {
s.Error(fmt.Sprintf("%s", err)) s.Error(fmt.Sprintf("%s", err))