mirror of
https://github.com/ffuf/ffuf
synced 2024-11-10 06:04:17 +00:00
Fix JSON output regression and Stdout race condition issues (#94)
* Fix json output regression and improve stdout printing * Add changelog entry
This commit is contained in:
parent
ac141e5e34
commit
7aad9c6051
4 changed files with 65 additions and 11 deletions
|
@ -155,7 +155,7 @@ Usage of ./ffuf:
|
|||
-o string
|
||||
Write output to file
|
||||
-of string
|
||||
Output file format. Available formats: json, html, md, csv, ecsv (default "json")
|
||||
Output file format. Available formats: json, ejson, html, md, csv, ecsv (default "json")
|
||||
-p delay
|
||||
Seconds of delay between requests, or a range of random delay. For example "0.1" or "0.1-2.0"
|
||||
-r Follow redirects
|
||||
|
@ -193,8 +193,10 @@ The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard l
|
|||
- master
|
||||
- New
|
||||
- Added a new flag to select a multi wordlist operation mode: `--mode`, possible values: `clusterbomb` and `pitchfork`.
|
||||
- Added a new output file format eJSON, for always base64 encoding the input data.
|
||||
- Changed
|
||||
- Fixed a bug in the default multi wordlist mode
|
||||
- Fixed JSON output regression, where all the input data was always encoded in base64
|
||||
|
||||
- v0.11
|
||||
|
||||
|
|
4
main.go
4
main.go
|
@ -92,7 +92,7 @@ func main() {
|
|||
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, html, md, csv, ecsv")
|
||||
flag.StringVar(&opts.outputFormat, "of", "json", "Output file format. Available formats: json, ejson, html, md, csv, ecsv")
|
||||
flag.BoolVar(&conf.ShowRedirectLocation, "l", false, "Show target location of redirect responses")
|
||||
flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)")
|
||||
flag.BoolVar(&conf.StopOn403, "sf", false, "Stop when > 95% of responses return 403 Forbidden")
|
||||
|
@ -333,7 +333,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", "html", "md", "csv", "ecsv"}
|
||||
outputFormats := []string{"json", "ejson", "html", "md", "csv", "ecsv"}
|
||||
found := false
|
||||
for _, f := range outputFormats {
|
||||
if f == parseOpts.outputFormat {
|
||||
|
|
|
@ -8,19 +8,68 @@ import (
|
|||
"github.com/ffuf/ffuf/pkg/ffuf"
|
||||
)
|
||||
|
||||
type jsonFileOutput struct {
|
||||
type ejsonFileOutput struct {
|
||||
CommandLine string `json:"commandline"`
|
||||
Time string `json:"time"`
|
||||
Results []Result `json:"results"`
|
||||
}
|
||||
|
||||
func writeJSON(config *ffuf.Config, res []Result) error {
|
||||
type JsonResult struct {
|
||||
Input map[string]string `json:"input"`
|
||||
Position int `json:"position"`
|
||||
StatusCode int64 `json:"status"`
|
||||
ContentLength int64 `json:"length"`
|
||||
ContentWords int64 `json:"words"`
|
||||
ContentLines int64 `json:"lines"`
|
||||
}
|
||||
|
||||
type jsonFileOutput struct {
|
||||
CommandLine string `json:"commandline"`
|
||||
Time string `json:"time"`
|
||||
Results []JsonResult `json:"results"`
|
||||
}
|
||||
|
||||
func writeEJSON(config *ffuf.Config, res []Result) error {
|
||||
t := time.Now()
|
||||
outJSON := jsonFileOutput{
|
||||
outJSON := ejsonFileOutput{
|
||||
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
|
||||
}
|
||||
|
||||
func writeJSON(config *ffuf.Config, res []Result) error {
|
||||
t := time.Now()
|
||||
jsonRes := make([]JsonResult, 0)
|
||||
for _, r := range res {
|
||||
strinput := make(map[string]string)
|
||||
for k, v := range r.Input {
|
||||
strinput[k] = string(v)
|
||||
}
|
||||
jsonRes = append(jsonRes, JsonResult{
|
||||
Input: strinput,
|
||||
Position: r.Position,
|
||||
StatusCode: r.StatusCode,
|
||||
ContentLength: r.ContentLength,
|
||||
ContentWords: r.ContentWords,
|
||||
ContentLines: r.ContentLines,
|
||||
})
|
||||
}
|
||||
outJSON := jsonFileOutput{
|
||||
CommandLine: config.CommandLine,
|
||||
Time: t.Format(time.RFC3339),
|
||||
Results: jsonRes,
|
||||
}
|
||||
outBytes, err := json.Marshal(outJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -110,6 +110,8 @@ func (s *Stdoutput) Finalize() error {
|
|||
if s.config.OutputFile != "" {
|
||||
if s.config.OutputFormat == "json" {
|
||||
err = writeJSON(s.config, s.Results)
|
||||
} else if s.config.OutputFormat == "ejson" {
|
||||
err = writeEJSON(s.config, s.Results)
|
||||
} else if s.config.OutputFormat == "html" {
|
||||
err = writeHTML(s.config, s.Results)
|
||||
} else if s.config.OutputFormat == "md" {
|
||||
|
@ -192,19 +194,20 @@ func (s *Stdoutput) resultQuiet(resp ffuf.Response) {
|
|||
|
||||
func (s *Stdoutput) resultMultiline(resp ffuf.Response) {
|
||||
var res_hdr, res_str string
|
||||
res_str = "%s * %s: %s\n"
|
||||
res_str = "%s%s * %s: %s\n"
|
||||
res_hdr = fmt.Sprintf("%s[Status: %d, Size: %d, Words: %d, Lines: %d%s]", TERMINAL_CLEAR_LINE, resp.StatusCode, resp.ContentLength, resp.ContentWords, resp.ContentLines, s.addRedirectLocation(resp))
|
||||
fmt.Println(s.colorize(res_hdr, resp.StatusCode))
|
||||
res_hdr = s.colorize(res_hdr, resp.StatusCode)
|
||||
reslines := ""
|
||||
for k, v := range resp.Request.Input {
|
||||
if inSlice(k, s.config.CommandKeywords) {
|
||||
// If we're using external command for input, display the position instead of input
|
||||
fmt.Printf(res_str, TERMINAL_CLEAR_LINE, k, strconv.Itoa(resp.Request.Position))
|
||||
reslines = fmt.Sprintf(res_str, reslines, TERMINAL_CLEAR_LINE, k, strconv.Itoa(resp.Request.Position))
|
||||
} else {
|
||||
// Wordlist input
|
||||
fmt.Printf(res_str, TERMINAL_CLEAR_LINE, k, v)
|
||||
reslines = fmt.Sprintf(res_str, reslines, TERMINAL_CLEAR_LINE, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n%s", res_hdr, reslines)
|
||||
}
|
||||
|
||||
func (s *Stdoutput) resultNormal(resp ffuf.Response) {
|
||||
|
|
Loading…
Reference in a new issue