mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 23:25:27 +00:00
* introducing execution id * wip * . * adding separate execution context id * lint * vet * fixing pg dialers * test ignore * fixing loader FD limit * test * fd fix * wip: remove CloseProcesses() from dev merge * wip: fix merge issue * protocolstate: stop memguarding on last dialer delete * avoid data race in dialers.RawHTTPClient * use shared logger and avoid race conditions * use shared logger and avoid race conditions * go mod * patch executionId into compiled template cache * clean up comment in Parse * go mod update * bump echarts * address merge issues * fix use of gologger * switch cmd/nuclei to options.Logger * address merge issues with go.mod * go vet: address copy of lock with new Copy function * fixing tests * disable speed control * fix nil ExecuterOptions * removing deprecated code * fixing result print * default logger * cli default logger * filter warning from results * fix performance test * hardcoding path * disable upload * refactor(runner): uses `Warning` instead of `Print` for `pdcpUploadErrMsg` Signed-off-by: Dwi Siswanto <git@dw1.io> * Revert "disable upload" This reverts commit 114fbe6663361bf41cf8b2645fd2d57083d53682. * Revert "hardcoding path" This reverts commit cf12ca800e0a0e974bd9fd4826a24e51547f7c00. --------- Signed-off-by: Dwi Siswanto <git@dw1.io> Co-authored-by: Mzack9999 <mzack9999@protonmail.com> Co-authored-by: Dwi Siswanto <git@dw1.io> Co-authored-by: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
154 lines
4.3 KiB
Go
154 lines
4.3 KiB
Go
package protocolstate
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"strings"
|
|
|
|
"github.com/go-rod/rod"
|
|
"github.com/go-rod/rod/lib/proto"
|
|
"github.com/projectdiscovery/networkpolicy"
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
|
errorutil "github.com/projectdiscovery/utils/errors"
|
|
stringsutil "github.com/projectdiscovery/utils/strings"
|
|
urlutil "github.com/projectdiscovery/utils/url"
|
|
"go.uber.org/multierr"
|
|
)
|
|
|
|
// initialize state of headless protocol
|
|
|
|
var (
|
|
ErrURLDenied = errorutil.NewWithFmt("headless: url %v dropped by rule: %v")
|
|
ErrHostDenied = errorutil.NewWithFmt("host %v dropped by network policy")
|
|
)
|
|
|
|
func GetNetworkPolicy(ctx context.Context) *networkpolicy.NetworkPolicy {
|
|
execCtx := GetExecutionContext(ctx)
|
|
if execCtx == nil {
|
|
return nil
|
|
}
|
|
dialers, ok := dialers.Get(execCtx.ExecutionID)
|
|
if !ok || dialers == nil {
|
|
return nil
|
|
}
|
|
return dialers.NetworkPolicy
|
|
}
|
|
|
|
// ValidateNFailRequest validates and fails request
|
|
// if the request does not respect the rules, it will be canceled with reason
|
|
func ValidateNFailRequest(options *types.Options, page *rod.Page, e *proto.FetchRequestPaused) error {
|
|
reqURL := e.Request.URL
|
|
normalized := strings.ToLower(reqURL) // normalize url to lowercase
|
|
normalized = strings.TrimSpace(normalized) // trim leading & trailing whitespaces
|
|
if !IsLfaAllowed(options) && stringsutil.HasPrefixI(normalized, "file:") {
|
|
return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "use of file:// protocol disabled use '-lfa' to enable"))
|
|
}
|
|
// validate potential invalid schemes
|
|
// javascript protocol is allowed for xss fuzzing
|
|
if stringsutil.HasPrefixAnyI(normalized, "ftp:", "externalfile:", "chrome:", "chrome-extension:") {
|
|
return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "protocol blocked by network policy"))
|
|
}
|
|
if !isValidHost(options, reqURL) {
|
|
return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "address blocked by network policy"))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FailWithReason fails request with AccessDenied reason
|
|
func FailWithReason(page *rod.Page, e *proto.FetchRequestPaused) error {
|
|
m := proto.FetchFailRequest{
|
|
RequestID: e.RequestID,
|
|
ErrorReason: proto.NetworkErrorReasonAccessDenied,
|
|
}
|
|
return m.Call(page)
|
|
}
|
|
|
|
// InitHeadless initializes headless protocol state
|
|
func InitHeadless(options *types.Options) {
|
|
dialers, ok := dialers.Get(options.ExecutionId)
|
|
if ok && dialers != nil {
|
|
dialers.Lock()
|
|
dialers.LocalFileAccessAllowed = options.AllowLocalFileAccess
|
|
dialers.RestrictLocalNetworkAccess = options.RestrictLocalNetworkAccess
|
|
dialers.Unlock()
|
|
}
|
|
}
|
|
|
|
// AllowLocalFileAccess returns whether local file access is allowed
|
|
func IsLfaAllowed(options *types.Options) bool {
|
|
dialers, ok := dialers.Get(options.ExecutionId)
|
|
if ok && dialers != nil {
|
|
dialers.Lock()
|
|
defer dialers.Unlock()
|
|
|
|
return dialers.LocalFileAccessAllowed
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IsRestrictLocalNetworkAccess(options *types.Options) bool {
|
|
dialers, ok := dialers.Get(options.ExecutionId)
|
|
if ok && dialers != nil {
|
|
dialers.Lock()
|
|
defer dialers.Unlock()
|
|
|
|
return dialers.RestrictLocalNetworkAccess
|
|
}
|
|
return false
|
|
}
|
|
|
|
// isValidHost checks if the host is valid (only limited to http/https protocols)
|
|
func isValidHost(options *types.Options, targetUrl string) bool {
|
|
if !stringsutil.HasPrefixAny(targetUrl, "http:", "https:") {
|
|
return true
|
|
}
|
|
|
|
dialers, ok := dialers.Get(options.ExecutionId)
|
|
if !ok {
|
|
return true
|
|
}
|
|
|
|
np := dialers.NetworkPolicy
|
|
if !ok || np == nil {
|
|
return true
|
|
}
|
|
|
|
urlx, err := urlutil.Parse(targetUrl)
|
|
if err != nil {
|
|
// not a valid url
|
|
return false
|
|
}
|
|
targetUrl = urlx.Hostname()
|
|
_, ok = np.ValidateHost(targetUrl)
|
|
return ok
|
|
}
|
|
|
|
// IsHostAllowed checks if the host is allowed by network policy
|
|
func IsHostAllowed(executionId string, targetUrl string) bool {
|
|
dialers, ok := dialers.Get(executionId)
|
|
if !ok {
|
|
return true
|
|
}
|
|
|
|
np := dialers.NetworkPolicy
|
|
if !ok || np == nil {
|
|
return true
|
|
}
|
|
|
|
sepCount := strings.Count(targetUrl, ":")
|
|
if sepCount > 1 {
|
|
// most likely a ipv6 address (parse url and validate host)
|
|
return np.Validate(targetUrl)
|
|
}
|
|
if sepCount == 1 {
|
|
host, _, _ := net.SplitHostPort(targetUrl)
|
|
if _, ok := np.ValidateHost(host); !ok {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
// just a hostname or ip without port
|
|
_, ok = np.ValidateHost(targetUrl)
|
|
return ok
|
|
}
|