Misc changes to headless

dev
Ice3man543 2021-03-01 14:20:56 +05:30
parent 20c3ec0857
commit 8a40fac305
7 changed files with 50 additions and 9 deletions

View File

@ -84,6 +84,7 @@ based on templates offering massive extensibility and ease of use.`)
set.BoolVarP(&options.Workflows, "workflows", "w", false, "Only run workflow templates with nuclei")
set.IntVarP(&options.StatsInterval, "stats-interval", "si", 5, "Number of seconds between each stats line")
set.BoolVar(&options.SystemResolvers, "system-resolvers", false, "Use system dns resolving as error fallback")
set.IntVar(&options.PageTimeout, "page-timeout", 15, "Seconds to wait for each page in headless")
_ = set.Parse()
if cfgFile != "" {

View File

@ -46,6 +46,10 @@ const (
ActionWaitEvent
// ActionKeyboard performs a keyboard action event on a page.
ActionKeyboard
// Action debug slows down headless and adds a sleep to each page.
ActionDebug
// ActionSleep executes a sleep for a specified duration
ActionSleep
)
// ActionStringToAction converts an action from string to internal representation
@ -69,6 +73,8 @@ var ActionStringToAction = map[string]ActionType{
"setbody": ActionSetBody,
"waitevent": ActionWaitEvent,
"keyboard": ActionKeyboard,
"debug": ActionDebug,
"sleep": ActionSleep,
}
// ActionToActionString converts an action from internal representation to string
@ -92,6 +98,8 @@ var ActionToActionString = map[ActionType]string{
ActionSetBody: "setbody",
ActionWaitEvent: "waitevent",
ActionKeyboard: "keyboard",
ActionDebug: "debug",
ActionSleep: "sleep",
}
// Action is an action taken by the browser to reach a navigation

View File

@ -2,6 +2,7 @@ package engine
import (
"net/url"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
@ -16,11 +17,13 @@ type Page struct {
}
// Run runs a list of actions by creating a new page in the browser.
func (i *Instance) Run(baseURL *url.URL, actions []*Action) (map[string]string, *Page, error) {
func (i *Instance) Run(baseURL *url.URL, actions []*Action, timeout time.Duration) (map[string]string, *Page, error) {
page, err := i.engine.Page(proto.TargetCreateTarget{})
if err != nil {
return nil, nil, err
}
page = page.Timeout(timeout)
if i.browser.customAgent != "" {
if userAgentErr := page.SetUserAgent(&proto.NetworkSetUserAgentOverride{UserAgent: i.browser.customAgent}); userAgentErr != nil {
return nil, nil, userAgentErr

View File

@ -63,6 +63,10 @@ func (p *Page) ExecuteActions(baseURL *url.URL, actions []*Action) (map[string]s
err = p.ActionSetMethod(act, outData)
case ActionKeyboard:
err = p.KeyboardAction(act, outData)
case ActionDebug:
err = p.DebugAction(act, outData)
case ActionSleep:
err = p.SleepAction(act, outData)
default:
continue
}
@ -467,6 +471,27 @@ func (p *Page) pageElementBy(data map[string]string) (*rod.Element, error) {
}
}
// DebugAction enables debug action on a page.
func (p *Page) DebugAction(act *Action, out map[string]string) error {
p.instance.browser.engine.SlowMotion(5 * time.Second)
p.instance.browser.engine.Trace(true)
return nil
}
// SleepAction sleeps on the page for a specified duration
func (p *Page) SleepAction(act *Action, out map[string]string) error {
seconds := act.Data["duration"]
if seconds == "" {
seconds = "5"
}
parsed, err := strconv.Atoi(seconds)
if err != nil {
return err
}
time.Sleep(time.Duration(parsed) * time.Second)
return nil
}
// selectorBy returns a selector from a representation.
func selectorBy(selector string) rod.SelectorType {
switch selector {

View File

@ -7,6 +7,7 @@ import (
"net/url"
"strings"
"testing"
"time"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/stretchr/testify/require"
@ -37,7 +38,7 @@ func TestActionNavigate(t *testing.T) {
require.Nil(t, err, "could not parse URL")
actions := []*Action{{ActionType: "navigate", Data: map[string]string{"url": "{{BaseURL}}"}}, {ActionType: "waitload"}}
_, page, err := instance.Run(parsed, actions)
_, page, err := instance.Run(parsed, actions, 20*time.Second)
require.Nil(t, err, "could not run page actions")
defer page.Close()
@ -73,7 +74,7 @@ func TestActionScript(t *testing.T) {
{ActionType: "waitload"},
{ActionType: "script", Name: "test", Data: map[string]string{"code": "window.test"}},
}
out, page, err := instance.Run(parsed, actions)
out, page, err := instance.Run(parsed, actions, 20*time.Second)
require.Nil(t, err, "could not run page actions")
defer page.Close()
@ -102,7 +103,7 @@ func TestActionScript(t *testing.T) {
{ActionType: "waitload"},
{ActionType: "script", Name: "test", Data: map[string]string{"code": "window.test"}},
}
out, page, err := instance.Run(parsed, actions)
out, page, err := instance.Run(parsed, actions, 20*time.Second)
require.Nil(t, err, "could not run page actions")
defer page.Close()
@ -139,7 +140,7 @@ func TestActionClick(t *testing.T) {
{ActionType: "waitload"},
{ActionType: "click", Data: map[string]string{"selector": "button"}}, // Use css selector for clicking
}
_, page, err := instance.Run(parsed, actions)
_, page, err := instance.Run(parsed, actions, 20*time.Second)
require.Nil(t, err, "could not run page actions")
defer page.Close()
@ -185,7 +186,7 @@ func TestActionRightClick(t *testing.T) {
{ActionType: "waitload"},
{ActionType: "rightclick", Data: map[string]string{"selector": "button"}}, // Use css selector for clicking
}
_, page, err := instance.Run(parsed, actions)
_, page, err := instance.Run(parsed, actions, 20*time.Second)
require.Nil(t, err, "could not run page actions")
defer page.Close()
@ -223,7 +224,7 @@ func TestActionTextInput(t *testing.T) {
{ActionType: "waitload"},
{ActionType: "text", Data: map[string]string{"selector": "input", "value": "test"}},
}
_, page, err := instance.Run(parsed, actions)
_, page, err := instance.Run(parsed, actions, 20*time.Second)
require.Nil(t, err, "could not run page actions")
defer page.Close()
@ -257,7 +258,7 @@ func TestActionHeadersChange(t *testing.T) {
{ActionType: "navigate", Data: map[string]string{"url": "{{BaseURL}}"}},
{ActionType: "waitload"},
}
_, page, err := instance.Run(parsed, actions)
_, page, err := instance.Run(parsed, actions, 20*time.Second)
require.Nil(t, err, "could not run page actions")
defer page.Close()

View File

@ -3,6 +3,7 @@ package headless
import (
"net/url"
"strings"
"time"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
@ -28,7 +29,7 @@ func (r *Request) ExecuteWithResults(input string, metadata, previous output.Int
r.options.Progress.DecrementRequests(1)
return errors.Wrap(err, "could get html element")
}
out, page, err := instance.Run(parsed, r.Steps)
out, page, err := instance.Run(parsed, r.Steps, time.Duration(r.options.Options.PageTimeout)*time.Second)
if err != nil {
r.options.Output.Request(r.options.TemplateID, input, "headless", err)
r.options.Progress.DecrementRequests(1)

View File

@ -55,6 +55,8 @@ type Options struct {
Retries int
// Rate-Limit is the maximum number of requests per specified target
RateLimit int
//`PageTimeout is the maximum time to wait for a page in seconds
PageTimeout int
// OfflineHTTP is a flag that specific offline processing of http response
// using same matchers/extractors from http protocol without the need
// to send a new request, reading responses from a file.