mirror of
https://github.com/ffuf/ffuf
synced 2024-11-10 06:04:17 +00:00
Option for JSON file output
This commit is contained in:
parent
3f3b5c31db
commit
baa8bdb6b5
4 changed files with 87 additions and 1 deletions
22
main.go
22
main.go
|
@ -28,6 +28,7 @@ type cliOptions struct {
|
|||
matcherRegexp string
|
||||
matcherWords string
|
||||
proxyURL string
|
||||
outputFormat string
|
||||
headers multiStringFlag
|
||||
showVersion bool
|
||||
}
|
||||
|
@ -65,6 +66,8 @@ func main() {
|
|||
flag.StringVar(&opts.matcherWords, "mw", "", "Match amount of words in response")
|
||||
flag.StringVar(&opts.proxyURL, "x", "", "HTTP Proxy URL")
|
||||
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")
|
||||
flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)")
|
||||
flag.IntVar(&conf.Threads, "t", 40, "Number of concurrent threads.")
|
||||
flag.BoolVar(&opts.showVersion, "V", false, "Show version information.")
|
||||
|
@ -179,6 +182,24 @@ 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"}
|
||||
found := false
|
||||
for _, f := range outputFormats {
|
||||
if f == parseOpts.outputFormat {
|
||||
conf.OutputFormat = f
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
errs.Add(fmt.Errorf("Unknown output file format (-of): %s", parseOpts.outputFormat))
|
||||
}
|
||||
}
|
||||
|
||||
conf.CommandLine = strings.Join(os.Args, " ")
|
||||
|
||||
//Search for keyword from URL and POST data too
|
||||
if strings.Index(conf.Url, "FUZZ") != -1 {
|
||||
foundkeyword = true
|
||||
|
@ -190,6 +211,7 @@ func prepareConfig(parseOpts *cliOptions, conf *ffuf.Config) error {
|
|||
if !foundkeyword {
|
||||
errs.Add(fmt.Errorf("No FUZZ keyword(s) found in headers, URL or POST data, nothing to do"))
|
||||
}
|
||||
|
||||
return errs.ErrorOrNil()
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,15 @@ type Config struct {
|
|||
Quiet bool
|
||||
Colors bool
|
||||
Wordlist string
|
||||
OutputFile string
|
||||
OutputFormat string
|
||||
Delay optRange
|
||||
Filters []FilterProvider
|
||||
Matchers []FilterProvider
|
||||
Threads int
|
||||
Context context.Context
|
||||
ProxyURL func(*http.Request) (*url.URL, error)
|
||||
CommandLine string
|
||||
}
|
||||
|
||||
func NewConfig(ctx context.Context) Config {
|
||||
|
|
33
pkg/output/file_json.go
Normal file
33
pkg/output/file_json.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package output
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/ffuf/ffuf/pkg/ffuf"
|
||||
)
|
||||
|
||||
type jsonFileOutput struct {
|
||||
CommandLine string `json:"commandline"`
|
||||
Time string `json:"time"`
|
||||
Results []Result `json:"results"`
|
||||
}
|
||||
|
||||
func writeJSON(config *ffuf.Config, res []Result) error {
|
||||
t := time.Now()
|
||||
outJSON := jsonFileOutput{
|
||||
CommandLine: config.CommandLine,
|
||||
Time: t.Format(time.RFC3339),
|
||||
Results: res,
|
||||
}
|
||||
outBytes, err := json.Marshal(outJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(config.OutputFile, outBytes, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -20,12 +20,21 @@ const (
|
|||
)
|
||||
|
||||
type Stdoutput struct {
|
||||
config *ffuf.Config
|
||||
config *ffuf.Config
|
||||
Results []Result
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Input string `json:"input"`
|
||||
StatusCode int64 `json:"status"`
|
||||
ContentLength int64 `json:"length"`
|
||||
ContentWords int64 `json:"words"`
|
||||
}
|
||||
|
||||
func NewStdoutput(conf *ffuf.Config) *Stdoutput {
|
||||
var outp Stdoutput
|
||||
outp.config = conf
|
||||
outp.Results = []Result{}
|
||||
return &outp
|
||||
}
|
||||
|
||||
|
@ -52,6 +61,15 @@ func (s *Stdoutput) Error(errstring string) {
|
|||
}
|
||||
|
||||
func (s *Stdoutput) Finalize() error {
|
||||
var err error
|
||||
if s.config.OutputFile != "" {
|
||||
if s.config.OutputFormat == "json" {
|
||||
err = writeJSON(s.config, s.Results)
|
||||
}
|
||||
if err != nil {
|
||||
s.Error(fmt.Sprintf("%s", err))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
return nil
|
||||
}
|
||||
|
@ -82,6 +100,16 @@ func (s *Stdoutput) Result(resp ffuf.Response) bool {
|
|||
}
|
||||
// Response survived the filtering, output the result
|
||||
s.printResult(resp)
|
||||
if s.config.OutputFile != "" {
|
||||
// No need to store results if we're not going to use them later
|
||||
sResult := Result{
|
||||
Input: string(resp.Request.Input),
|
||||
StatusCode: resp.StatusCode,
|
||||
ContentLength: resp.ContentLength,
|
||||
ContentWords: resp.ContentWords,
|
||||
}
|
||||
s.Results = append(s.Results, sResult)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue