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.
@ -172,23 +171,27 @@ eg. `ffuf -u https://example.org/FUZZ -w /path/to/wordlist`
## Installation ## Installation
- [Download](https://github.com/ffuf/ffuf/releases/latest) a prebuilt binary from [releases page](https://github.com/ffuf/ffuf/releases/latest), unpack and run! - [Download](https://github.com/ffuf/ffuf/releases/latest) a prebuilt binary from [releases page](https://github.com/ffuf/ffuf/releases/latest), unpack and run!
or or
- If you have go compiler installed: `go get github.com/ffuf/ffuf` - If you have go compiler installed: `go get github.com/ffuf/ffuf`
The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard library are needed. The only dependency of ffuf is Go 1.11. No dependencies outside of Go standard library are needed.
## 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,8 +220,9 @@ 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!
- Optional scope for redirects - Tests!
- Client / server architecture to queue jobs and fetch the results later - Optional scope for redirects
- Fuzzing multiple values at the same time - Client / server architecture to queue jobs and fetch the results later
- Output module to push the results to an HTTP API - Fuzzing multiple values at the same time
- Output module to push the results to an HTTP API

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 {