From ff1bc2a3c2b357f419982607623c96f456affd9b Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Mon, 17 Feb 2020 00:56:38 +0200 Subject: [PATCH] Handle relative URLs in redirects properly (#167) --- CHANGELOG.md | 1 + pkg/ffuf/job.go | 6 +++--- pkg/ffuf/response.go | 15 ++++++++++++++- pkg/output/stdout.go | 4 ++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a411281..f2514f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Changed - Write POST request data properly to file when ran with `-od` + - Properly handle relative redirect urls with `-recursion` - v1.0.1 - Changed diff --git a/pkg/ffuf/job.go b/pkg/ffuf/job.go index 090cb85..3e8649c 100644 --- a/pkg/ffuf/job.go +++ b/pkg/ffuf/job.go @@ -279,7 +279,7 @@ func (j *Job) runTask(input map[string][]byte, position int, retried bool) { j.updateProgress() } - if j.Config.Recursion && len(resp.GetRedirectLocation()) > 0 { + if j.Config.Recursion && len(resp.GetRedirectLocation(false)) > 0 { j.handleRecursionJob(resp) } return @@ -287,7 +287,7 @@ func (j *Job) runTask(input map[string][]byte, position int, retried bool) { //handleRecursionJob adds a new recursion job to the job queue if a new directory is found func (j *Job) handleRecursionJob(resp Response) { - if (resp.Request.Url + "/") != resp.GetRedirectLocation() { + if (resp.Request.Url + "/") != resp.GetRedirectLocation(true) { // Not a directory, return early return } @@ -298,7 +298,7 @@ func (j *Job) handleRecursionJob(resp Response) { j.queuejobs = append(j.queuejobs, newJob) j.Output.Info(fmt.Sprintf("Adding a new job to the queue: %s", recUrl)) } else { - j.Output.Warning(fmt.Sprintf("Directory found, but recursion depth exceeded. Ignoring: %s", resp.GetRedirectLocation())) + j.Output.Warning(fmt.Sprintf("Directory found, but recursion depth exceeded. Ignoring: %s", resp.GetRedirectLocation(true))) } } diff --git a/pkg/ffuf/response.go b/pkg/ffuf/response.go index f6119df..2da127b 100644 --- a/pkg/ffuf/response.go +++ b/pkg/ffuf/response.go @@ -2,6 +2,7 @@ package ffuf import ( "net/http" + "net/url" ) // Response struct holds the meaningful data returned from request and is meant for passing to filters @@ -19,13 +20,25 @@ type Response struct { } // GetRedirectLocation returns the redirect location for a 3xx redirect HTTP response -func (resp *Response) GetRedirectLocation() string { +func (resp *Response) GetRedirectLocation(absolute bool) string { redirectLocation := "" if resp.StatusCode >= 300 && resp.StatusCode <= 399 { redirectLocation = resp.Headers["Location"][0] } + if absolute { + redirectUrl, err := url.Parse(redirectLocation) + if err != nil { + return redirectLocation + } + baseUrl, err := url.Parse(resp.Request.Url) + if err != nil { + return redirectLocation + } + redirectLocation = baseUrl.ResolveReference(redirectUrl).String() + } + return redirectLocation } diff --git a/pkg/output/stdout.go b/pkg/output/stdout.go index 2183b96..da71bc1 100644 --- a/pkg/output/stdout.go +++ b/pkg/output/stdout.go @@ -233,7 +233,7 @@ func (s *Stdoutput) Result(resp ffuf.Response) { ContentLength: resp.ContentLength, ContentWords: resp.ContentWords, ContentLines: resp.ContentLines, - RedirectLocation: resp.GetRedirectLocation(), + RedirectLocation: resp.GetRedirectLocation(false), Url: resp.Request.Url, ResultFile: resp.ResultFile, } @@ -315,7 +315,7 @@ func (s *Stdoutput) resultMultiline(resp ffuf.Response) { reslines := "" if s.config.Verbose { reslines = fmt.Sprintf("%s%s| URL | %s\n", reslines, TERMINAL_CLEAR_LINE, resp.Request.Url) - redirectLocation := resp.GetRedirectLocation() + redirectLocation := resp.GetRedirectLocation(false) if redirectLocation != "" { reslines = fmt.Sprintf("%s%s| --> | %s\n", reslines, TERMINAL_CLEAR_LINE, redirectLocation) }