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,53 +171,58 @@ 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
- Changed - New
- New CLI flag: -i, dummy flag that does nothing. for compatibility with copy as curl. - New CLI flag: -l, shows target location of redirect responses
- New CLI flag: -b/--cookie, cookie data for compatibility with copy as curl. - Changed
- Filtering and matching by status code, response size or word count now allow using ranges in addition to single values - 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.
- 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 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: --data for compatibility with copy as curl functionality of browsers.
- New CLI flag: --compressed, dummy flag that does nothing. for compatibility with copy as curl.
- New CLI flags: --input-cmd, and --input-num to handle input generation using external commands. Mutators for example. Environment variable FFUF_NUM will be updated on every call of the command.
- When --input-cmd is used, display position instead of the payload in results. The output file (of all formats) will include the payload in addition to the position however.
- Changed - New
- Wordlist can also be read from standard input
- Defining -d or --data implies POST method if -X doesn't set it to something else than GET - 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: --data for compatibility with copy as curl functionality of browsers.
- New CLI flag: --compressed, dummy flag that does nothing. for compatibility with copy as curl.
- New CLI flags: --input-cmd, and --input-num to handle input generation using external commands. Mutators for example. Environment variable FFUF_NUM will be updated on every call of the command.
- When --input-cmd is used, display position instead of the payload in results. The output file (of all formats) will include the payload in addition to the position however.
- Changed
- Wordlist can also be read from standard input
- Defining -d or --data implies POST method if -X doesn't set it to something else than GET
- v0.9 - v0.9
- New - New
- New output file formats: CSV and eCSV (CSV with base64 encoded input field to avoid CSV breakage with payloads containing a comma) - New output file formats: CSV and eCSV (CSV with base64 encoded input field to avoid CSV breakage with payloads containing a comma)
- New CLI flag to follow redirects - New CLI flag to follow redirects
- Erroring connections will be retried once - Erroring connections will be retried once
- Error counter in status bar - Error counter in status bar
- New CLI flags: -se (stop on spurious errors) and -sa (stop on all errors, implies -se and -sf) - New CLI flags: -se (stop on spurious errors) and -sa (stop on all errors, implies -se and -sf)
- New CLI flags: -e to provide a list of extensions to add to wordlist entries, and -D to provide DirSearch wordlist format compatibility. - New CLI flags: -e to provide a list of extensions to add to wordlist entries, and -D to provide DirSearch wordlist format compatibility.
- Wildcard option for response status code matcher. - Wildcard option for response status code matcher.
- v0.8 - v0.8
- New - New
- New CLI flag to write output to a file in JSON format - New CLI flag to write output to a file in JSON format
- New CLI flag to stop on spurious 403 responses - New CLI flag to stop on spurious 403 responses
- Changed - Changed
- 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

@ -16,35 +16,36 @@ type optRange struct {
} }
type Config struct { type Config struct {
StaticHeaders map[string]string StaticHeaders map[string]string
FuzzHeaders map[string]string FuzzHeaders map[string]string
Extensions []string Extensions []string
DirSearchCompat bool DirSearchCompat bool
Method string Method string
Url string Url string
TLSVerify bool TLSVerify bool
Data string Data string
Quiet bool Quiet bool
Colors bool Colors bool
Wordlist string Wordlist string
InputCommand string InputCommand string
InputNum int InputNum int
OutputFile string OutputFile string
OutputFormat string OutputFormat string
StopOn403 bool StopOn403 bool
StopOnErrors bool StopOnErrors bool
StopOnAll bool StopOnAll bool
FollowRedirects bool FollowRedirects bool
AutoCalibration bool AutoCalibration bool
Timeout int ShowRedirectLocation bool
ProgressFrequency int Timeout int
Delay optRange ProgressFrequency int
Filters []FilterProvider Delay optRange
Matchers []FilterProvider Filters []FilterProvider
Threads int Matchers []FilterProvider
Context context.Context Threads int
ProxyURL func(*http.Request) (*url.URL, error) Context context.Context
CommandLine string ProxyURL func(*http.Request) (*url.URL, error)
CommandLine string
} }
func NewConfig(ctx context.Context) Config { func NewConfig(ctx context.Context) Config {
@ -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 {