diff --git a/pkg/protocols/headless/engine/page.go b/pkg/protocols/headless/engine/page.go index fd8687e142..4dca72a6a9 100644 --- a/pkg/protocols/headless/engine/page.go +++ b/pkg/protocols/headless/engine/page.go @@ -24,19 +24,20 @@ import ( // Page is a single page in an isolated browser instance type Page struct { - ctx *contextargs.Context - inputURL *urlutil.URL - options *Options - page *rod.Page - rules []rule - instance *Instance - hijackRouter *rod.HijackRouter - hijackNative *Hijack - mutex *sync.RWMutex - History []HistoryData - InteractshURLs []string - payloads map[string]interface{} - variables map[string]interface{} + ctx *contextargs.Context + inputURL *urlutil.URL + options *Options + page *rod.Page + rules []rule + instance *Instance + hijackRouter *rod.HijackRouter + hijackNative *Hijack + mutex *sync.RWMutex + History []HistoryData + InteractshURLs []string + payloads map[string]interface{} + variables map[string]interface{} + lastActionNavigate *Action } // HistoryData contains the page request/response pairs @@ -274,6 +275,17 @@ func (p *Page) hasModificationRules() bool { return false } +// updateLastNavigatedURL updates the last navigated URL in the instance's +// request log. +func (p *Page) updateLastNavigatedURL() { + if p.lastActionNavigate == nil { + return + } + + templateURL := p.lastActionNavigate.GetArg("url") + p.instance.requestLog[templateURL] = p.URL() +} + func containsModificationActions(actions ...*Action) bool { for _, action := range actions { if containsAnyModificationActionType(action.ActionType.ActionType) { diff --git a/pkg/protocols/headless/engine/page_actions.go b/pkg/protocols/headless/engine/page_actions.go index a0b001daff..204ce8eeab 100644 --- a/pkg/protocols/headless/engine/page_actions.go +++ b/pkg/protocols/headless/engine/page_actions.go @@ -47,6 +47,7 @@ const ( // ExecuteActions executes a list of actions on a page. func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action) (outData ActionData, err error) { outData = make(ActionData) + // waitFuncs are function that needs to be executed after navigation // typically used for waitEvent waitFuncs := make([]func() error, 0) @@ -76,6 +77,8 @@ func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action) (ou } } } + + p.lastActionNavigate = act } case ActionScript: err = p.RunScript(act, outData) @@ -407,12 +410,12 @@ func (p *Page) NavigateURL(action *Action, out ActionData) error { finalparams.Merge(p.inputURL.Params.Encode()) parsedURL.Params = finalparams - // log all navigated requests - p.instance.requestLog[action.GetArg("url")] = parsedURL.String() - if err := p.page.Navigate(parsedURL.String()); err != nil { return errorutil.NewWithErr(err).Msgf("could not navigate to url %s", parsedURL.String()) } + + p.updateLastNavigatedURL() + return nil } @@ -667,6 +670,9 @@ func (p *Page) WaitPageLifecycleEvent(act *Action, out ActionData, event proto.P fn() + // log the navigated request (even if it is a redirect) + p.updateLastNavigatedURL() + return nil } @@ -687,7 +693,14 @@ func (p *Page) WaitStable(act *Action, out ActionData) error { } } - return p.page.Timeout(timeout).WaitStable(dur) + if err := p.page.Timeout(timeout).WaitStable(dur); err != nil { + return err + } + + // log the navigated request (even if it is a redirect) + p.updateLastNavigatedURL() + + return nil } // GetResource gets a resource from an element from page. diff --git a/pkg/protocols/headless/request.go b/pkg/protocols/headless/request.go index 22a33bf7f3..83280ee630 100644 --- a/pkg/protocols/headless/request.go +++ b/pkg/protocols/headless/request.go @@ -2,6 +2,7 @@ package headless import ( "fmt" + "maps" "net/url" "strings" "time" @@ -9,7 +10,6 @@ import ( "github.com/projectdiscovery/retryablehttp-go" "github.com/pkg/errors" - "golang.org/x/exp/maps" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/nuclei/v3/pkg/fuzz" @@ -189,12 +189,9 @@ func (request *Request) executeRequestWithPayloads(input *contextargs.Context, p if request.options.HasTemplateCtx(input.MetaInput) { outputEvent = generators.MergeMaps(outputEvent, request.options.GetTemplateCtx(input.MetaInput).GetAll()) } - for k, v := range out { - outputEvent[k] = v - } - for k, v := range payloads { - outputEvent[k] = v - } + + maps.Copy(outputEvent, out) + maps.Copy(outputEvent, payloads) var event *output.InternalWrappedEvent if len(page.InteractshURLs) == 0 {