Added redirect location in stdout output (#59)

* Added redirect location in stdout output

* Keep conditional logic outside of the resultNormal function + Better help message for redirect location

* Moved GetRedirectLocation as a Response public method

* Added changelog entry + (Redirect become ->)
This commit is contained in:
SakiiR 2019-10-14 10:29:37 +02:00 committed by Joona Hoikkala
parent 55662e607a
commit 081e40f97e
5 changed files with 99 additions and 70 deletions

View File

@ -7,7 +7,6 @@
\/_/ \/_/ \/___/ \/_/ \/_/ \/_/ \/___/ \/_/
``` ```
# ffuf - Fuzz Faster U Fool # ffuf - Fuzz Faster U Fool
A fast web fuzzer written in Go. A fast web fuzzer written in Go.
@ -181,14 +180,18 @@ The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard l
## Changelog ## Changelog
- master - master
- New - New
- New CLI flag: -l, shows target location of redirect responses
- Changed - Changed
- New CLI flag: -i, dummy flag that does nothing. for compatibility with copy as curl. - New CLI flag: -i, dummy flag that does nothing. for compatibility with copy as curl.
- New CLI flag: -b/--cookie, cookie data for compatibility with copy as curl. - New CLI flag: -b/--cookie, cookie data for compatibility with copy as curl.
- Filtering and matching by status code, response size or word count now allow using ranges in addition to single values - Filtering and matching by status code, response size or word count now allow using ranges in addition to single values
- v0.10 - v0.10
- New - New
- New CLI flag: -ac to autocalibrate response size and word filters based on few preset URLs. - New CLI flag: -ac to autocalibrate response size and word filters based on few preset URLs.
- New CLI flag: -timeout to specify custom timeouts for all HTTP requests. - New CLI flag: -timeout to specify custom timeouts for all HTTP requests.
- New CLI flag: --data for compatibility with copy as curl functionality of browsers. - New CLI flag: --data for compatibility with copy as curl functionality of browsers.
@ -217,6 +220,7 @@ The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard l
- Regex matching / filtering now matches the headers alongside of the response body - Regex matching / filtering now matches the headers alongside of the response body
## TODO ## TODO
- Tests! - Tests!
- Optional scope for redirects - Optional scope for redirects
- Client / server architecture to queue jobs and fetch the results later - Client / server architecture to queue jobs and fetch the results later

View File

@ -82,6 +82,7 @@ func main() {
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, csv, ecsv") flag.StringVar(&opts.outputFormat, "of", "json", "Output file format. Available formats: json, 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.Quiet, "s", false, "Do not print additional information (silent mode)")
flag.BoolVar(&conf.StopOn403, "sf", false, "Stop when > 95% of responses return 403 Forbidden") flag.BoolVar(&conf.StopOn403, "sf", false, "Stop when > 95% of responses return 403 Forbidden")
flag.BoolVar(&conf.StopOnErrors, "se", false, "Stop on spurious errors") flag.BoolVar(&conf.StopOnErrors, "se", false, "Stop on spurious errors")

View File

@ -36,6 +36,7 @@ type Config struct {
StopOnAll bool StopOnAll bool
FollowRedirects bool FollowRedirects bool
AutoCalibration bool AutoCalibration bool
ShowRedirectLocation bool
Timeout int Timeout int
ProgressFrequency int ProgressFrequency int
Delay optRange Delay optRange
@ -60,6 +61,7 @@ func NewConfig(ctx context.Context) Config {
conf.StopOn403 = false conf.StopOn403 = false
conf.StopOnErrors = false conf.StopOnErrors = false
conf.StopOnAll = false conf.StopOnAll = false
conf.ShowRedirectLocation = false
conf.FollowRedirects = false conf.FollowRedirects = false
conf.InputCommand = "" conf.InputCommand = ""
conf.InputNum = 0 conf.InputNum = 0

View File

@ -15,6 +15,17 @@ type Response struct {
Request *Request Request *Request
} }
// GetRedirectLocation returns the redirect location for a 3xx redirect HTTP response
func (resp *Response) GetRedirectLocation() string {
redirectLocation := ""
if resp.StatusCode >= 300 && resp.StatusCode <= 399 {
redirectLocation = resp.Headers["Location"][0]
}
return redirectLocation
}
func NewResponse(httpresp *http.Response, req *Request) Response { func NewResponse(httpresp *http.Response, req *Request) Response {
var resp Response var resp Response
resp.Request = req resp.Request = req

View File

@ -156,14 +156,25 @@ func (s *Stdoutput) resultQuiet(resp ffuf.Response) {
} }
func (s *Stdoutput) resultNormal(resp ffuf.Response) { func (s *Stdoutput) resultNormal(resp ffuf.Response) {
var res_str string var responseString string
if len(s.config.InputCommand) > 0 { if len(s.config.InputCommand) > 0 {
// If we're using external command for input, display the position instead of input // If we're using external command for input, display the position instead of input
res_str = fmt.Sprintf("%s%-23s [Status: %s, Size: %d, Words: %d]", TERMINAL_CLEAR_LINE, strconv.Itoa(resp.Request.Position), s.colorizeStatus(resp.StatusCode), resp.ContentLength, resp.ContentWords) responseString = fmt.Sprintf("%s%-23s [Status: %s, Size: %d, Words: %d%s]", TERMINAL_CLEAR_LINE, strconv.Itoa(resp.Request.Position), s.colorizeStatus(resp.StatusCode), resp.ContentLength, resp.ContentWords, s.addRedirectLocation(resp))
} else { } else {
res_str = fmt.Sprintf("%s%-23s [Status: %s, Size: %d, Words: %d]", TERMINAL_CLEAR_LINE, resp.Request.Input, s.colorizeStatus(resp.StatusCode), resp.ContentLength, resp.ContentWords) responseString = fmt.Sprintf("%s%-23s [Status: %s, Size: %d, Words: %d%s]", TERMINAL_CLEAR_LINE, resp.Request.Input, s.colorizeStatus(resp.StatusCode), resp.ContentLength, resp.ContentWords, s.addRedirectLocation(resp))
} }
fmt.Println(res_str) fmt.Println(responseString)
}
// addRedirectLocation returns a formatted string containing the Redirect location or returns an empty string
func (s *Stdoutput) addRedirectLocation(resp ffuf.Response) string {
if s.config.ShowRedirectLocation == true {
redirectLocation := resp.GetRedirectLocation()
if redirectLocation != "" {
return fmt.Sprintf(", ->: %s", redirectLocation)
}
}
return ""
} }
func (s *Stdoutput) colorizeStatus(status int64) string { func (s *Stdoutput) colorizeStatus(status int64) string {