mirror of https://github.com/daffainfo/nuclei.git
adds `-track-error` option to add custom errors to max-host-error watchlist (#3399)
* Allow user to specify for "context deadline exceeded" errors to count toward the max host error count * Convert flag to a string slice `--track-error` * Minimize diff * Add documentation for `-track-error` * adds unit test & minor improvements * update flag description --------- Co-authored-by: Austin Traver <austin_traver@intuit.com> Co-authored-by: Tarun Koyalwar <tarun@projectdiscovery.io>dev
parent
bcb1a8811d
commit
0d90a555f6
|
@ -225,6 +225,7 @@ OPTIMIZATIONS:
|
||||||
-retries int number of times to retry a failed request (default 1)
|
-retries int number of times to retry a failed request (default 1)
|
||||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||||
|
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||||
-project use a project folder to avoid sending same request multiple times
|
-project use a project folder to avoid sending same request multiple times
|
||||||
-project-path string set a specific project path (default "/tmp")
|
-project-path string set a specific project path (default "/tmp")
|
||||||
|
|
|
@ -189,6 +189,7 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
|
||||||
-retries int 重试次数(默认:1)
|
-retries int 重试次数(默认:1)
|
||||||
-ldp, -leave-default-ports 指定HTTP/HTTPS默认端口(例如:host:80,host:443)
|
-ldp, -leave-default-ports 指定HTTP/HTTPS默认端口(例如:host:80,host:443)
|
||||||
-mhe, -max-host-error int 某主机扫描失败次数,跳过该主机(默认:30)
|
-mhe, -max-host-error int 某主机扫描失败次数,跳过该主机(默认:30)
|
||||||
|
-te, -track-error string[] 将给定错误添加到最大主机错误监视列表(标准、文件)
|
||||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||||
-project 使用项目文件夹避免多次发送同一请求
|
-project 使用项目文件夹避免多次发送同一请求
|
||||||
-project-path string 设置特定的项目文件夹
|
-project-path string 设置特定的项目文件夹
|
||||||
|
|
|
@ -188,6 +188,7 @@ OPTIMIZATIONS:
|
||||||
-retries int number of times to retry a failed request (default 1)
|
-retries int number of times to retry a failed request (default 1)
|
||||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443
|
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443
|
||||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||||
|
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||||
-project use a project folder to avoid sending same request multiple times
|
-project use a project folder to avoid sending same request multiple times
|
||||||
-project-path string set a specific project path
|
-project-path string set a specific project path
|
||||||
|
|
|
@ -178,6 +178,7 @@ OPTIMIZATIONS:
|
||||||
-retries int 실패한 요청을 재시도하는 횟수 (기본 1)
|
-retries int 실패한 요청을 재시도하는 횟수 (기본 1)
|
||||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443
|
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443
|
||||||
-mhe, -max-host-error int 스캔을 건너뛰기 전에 호스트에 대한 최대 오류 수 (기본 30)
|
-mhe, -max-host-error int 스캔을 건너뛰기 전에 호스트에 대한 최대 오류 수 (기본 30)
|
||||||
|
-te, -track-error string[] 주어진 오류를 max-host-error 감시 목록(표준, 파일)에 추가
|
||||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||||
-project 프로젝트 폴더를 사용하여 동일한 요청을 여러 번 보내지 않음
|
-project 프로젝트 폴더를 사용하여 동일한 요청을 여러 번 보내지 않음
|
||||||
-project-path string 특정 프로젝트 경로 설정
|
-project-path string 특정 프로젝트 경로 설정
|
||||||
|
|
|
@ -65,7 +65,7 @@ func (h *goIntegrationTest) Execute(templatePath string) error {
|
||||||
|
|
||||||
// executeNucleiAsCode contains an example
|
// executeNucleiAsCode contains an example
|
||||||
func executeNucleiAsCode(templatePath, templateURL string) ([]string, error) {
|
func executeNucleiAsCode(templatePath, templateURL string) ([]string, error) {
|
||||||
cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount)
|
cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount, nil)
|
||||||
defer cache.Close()
|
defer cache.Close()
|
||||||
|
|
||||||
mockProgress := &testutils.MockProgressClient{}
|
mockProgress := &testutils.MockProgressClient{}
|
||||||
|
|
|
@ -249,6 +249,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||||
flagSet.IntVar(&options.Retries, "retries", 1, "number of times to retry a failed request"),
|
flagSet.IntVar(&options.Retries, "retries", 1, "number of times to retry a failed request"),
|
||||||
flagSet.BoolVarP(&options.LeaveDefaultPorts, "leave-default-ports", "ldp", false, "leave default HTTP/HTTPS ports (eg. host:80,host:443)"),
|
flagSet.BoolVarP(&options.LeaveDefaultPorts, "leave-default-ports", "ldp", false, "leave default HTTP/HTTPS ports (eg. host:80,host:443)"),
|
||||||
flagSet.IntVarP(&options.MaxHostError, "max-host-error", "mhe", 30, "max errors for a host before skipping from scan"),
|
flagSet.IntVarP(&options.MaxHostError, "max-host-error", "mhe", 30, "max errors for a host before skipping from scan"),
|
||||||
|
flagSet.StringSliceVarP(&options.TrackError, "track-error", "te", nil, "adds given error to max-host-error watchlist (standard, file)", goflags.FileStringSliceOptions),
|
||||||
flagSet.BoolVarP(&options.NoHostErrors, "no-mhe", "nmhe", false, "disable skipping host from scan based on errors"),
|
flagSet.BoolVarP(&options.NoHostErrors, "no-mhe", "nmhe", false, "disable skipping host from scan based on errors"),
|
||||||
flagSet.BoolVar(&options.Project, "project", false, "use a project folder to avoid sending same request multiple times"),
|
flagSet.BoolVar(&options.Project, "project", false, "use a project folder to avoid sending same request multiple times"),
|
||||||
flagSet.StringVar(&options.ProjectPath, "project-path", os.TempDir(), "set a specific project path"),
|
flagSet.StringVar(&options.ProjectPath, "project-path", os.TempDir(), "set a specific project path"),
|
||||||
|
@ -334,7 +335,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||||
_ = flagSet.Parse()
|
_ = flagSet.Parse()
|
||||||
|
|
||||||
gologger.DefaultLogger.SetTimestamp(options.Timestamp, levels.LevelDebug)
|
gologger.DefaultLogger.SetTimestamp(options.Timestamp, levels.LevelDebug)
|
||||||
|
|
||||||
if options.LeaveDefaultPorts {
|
if options.LeaveDefaultPorts {
|
||||||
http.LeaveDefaultPorts = true
|
http.LeaveDefaultPorts = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount)
|
cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount, nil)
|
||||||
defer cache.Close()
|
defer cache.Close()
|
||||||
|
|
||||||
mockProgress := &testutils.MockProgressClient{}
|
mockProgress := &testutils.MockProgressClient{}
|
||||||
|
|
|
@ -411,7 +411,7 @@ func (r *Runner) RunEnumeration() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.options.ShouldUseHostError() {
|
if r.options.ShouldUseHostError() {
|
||||||
cache := hosterrorscache.New(r.options.MaxHostError, hosterrorscache.DefaultMaxHostsCount)
|
cache := hosterrorscache.New(r.options.MaxHostError, hosterrorscache.DefaultMaxHostsCount, r.options.TrackError)
|
||||||
cache.SetVerbose(r.options.Verbose)
|
cache.SetVerbose(r.options.Verbose)
|
||||||
r.hostErrors = cache
|
r.hostErrors = cache
|
||||||
executerOpts.HostErrorsCache = cache
|
executerOpts.HostErrorsCache = cache
|
||||||
|
|
|
@ -30,6 +30,7 @@ type Cache struct {
|
||||||
MaxHostError int
|
MaxHostError int
|
||||||
verbose bool
|
verbose bool
|
||||||
failedTargets gcache.Cache
|
failedTargets gcache.Cache
|
||||||
|
TrackError []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type cacheItem struct {
|
type cacheItem struct {
|
||||||
|
@ -40,11 +41,11 @@ type cacheItem struct {
|
||||||
const DefaultMaxHostsCount = 10000
|
const DefaultMaxHostsCount = 10000
|
||||||
|
|
||||||
// New returns a new host max errors cache
|
// New returns a new host max errors cache
|
||||||
func New(maxHostError, maxHostsCount int) *Cache {
|
func New(maxHostError, maxHostsCount int, trackError []string) *Cache {
|
||||||
gc := gcache.New(maxHostsCount).
|
gc := gcache.New(maxHostsCount).
|
||||||
ARC().
|
ARC().
|
||||||
Build()
|
Build()
|
||||||
return &Cache{failedTargets: gc, MaxHostError: maxHostError}
|
return &Cache{failedTargets: gc, MaxHostError: maxHostError, TrackError: trackError}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetVerbose sets the cache to log at verbose level
|
// SetVerbose sets the cache to log at verbose level
|
||||||
|
@ -128,6 +129,14 @@ var reCheckError = regexp.MustCompile(`(no address found for host|Client\.Timeou
|
||||||
// checkError checks if an error represents a type that should be
|
// checkError checks if an error represents a type that should be
|
||||||
// added to the host skipping table.
|
// added to the host skipping table.
|
||||||
func (c *Cache) checkError(err error) bool {
|
func (c *Cache) checkError(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
errString := err.Error()
|
errString := err.Error()
|
||||||
|
for _, msg := range c.TrackError {
|
||||||
|
if strings.Contains(errString, msg) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
return reCheckError.MatchString(errString)
|
return reCheckError.MatchString(errString)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCacheCheck(t *testing.T) {
|
func TestCacheCheck(t *testing.T) {
|
||||||
cache := New(3, DefaultMaxHostsCount)
|
cache := New(3, DefaultMaxHostsCount, nil)
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
cache.MarkFailed("test", fmt.Errorf("could not resolve host"))
|
cache.MarkFailed("test", fmt.Errorf("could not resolve host"))
|
||||||
|
@ -28,6 +28,24 @@ func TestCacheCheck(t *testing.T) {
|
||||||
require.Equal(t, true, value, "could not get checked value")
|
require.Equal(t, true, value, "could not get checked value")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrackErrors(t *testing.T) {
|
||||||
|
cache := New(3, DefaultMaxHostsCount, []string{"custom error"})
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
cache.MarkFailed("custom", fmt.Errorf("got: nested: custom error"))
|
||||||
|
got := cache.Check("custom")
|
||||||
|
if i < 2 {
|
||||||
|
// till 3 the host is not flagged to skip
|
||||||
|
require.False(t, got)
|
||||||
|
} else {
|
||||||
|
// above 3 it must remain flagged to skip
|
||||||
|
require.True(t, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value := cache.Check("custom")
|
||||||
|
require.Equal(t, true, value, "could not get checked value")
|
||||||
|
}
|
||||||
|
|
||||||
func TestCacheItemDo(t *testing.T) {
|
func TestCacheItemDo(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
count int
|
count int
|
||||||
|
@ -51,7 +69,7 @@ func TestCacheItemDo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheMarkFailed(t *testing.T) {
|
func TestCacheMarkFailed(t *testing.T) {
|
||||||
cache := New(3, DefaultMaxHostsCount)
|
cache := New(3, DefaultMaxHostsCount, nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
host string
|
host string
|
||||||
|
@ -76,7 +94,7 @@ func TestCacheMarkFailed(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheMarkFailedConcurrent(t *testing.T) {
|
func TestCacheMarkFailedConcurrent(t *testing.T) {
|
||||||
cache := New(3, DefaultMaxHostsCount)
|
cache := New(3, DefaultMaxHostsCount, nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
host string
|
host string
|
||||||
|
|
|
@ -139,6 +139,8 @@ type Options struct {
|
||||||
MetricsPort int
|
MetricsPort int
|
||||||
// MaxHostError is the maximum number of errors allowed for a host
|
// MaxHostError is the maximum number of errors allowed for a host
|
||||||
MaxHostError int
|
MaxHostError int
|
||||||
|
// TrackError contains additional error messages that count towards the maximum number of errors allowed for a host
|
||||||
|
TrackError goflags.StringSlice
|
||||||
// NoHostErrors disables host skipping after maximum number of errors
|
// NoHostErrors disables host skipping after maximum number of errors
|
||||||
NoHostErrors bool
|
NoHostErrors bool
|
||||||
// BulkSize is the of targets analyzed in parallel for each template
|
// BulkSize is the of targets analyzed in parallel for each template
|
||||||
|
|
Loading…
Reference in New Issue