2020-04-04 15:59:05 +05:30
|
|
|
package runner
|
|
|
|
|
|
|
|
|
|
import (
|
2022-03-03 19:44:29 +05:30
|
|
|
"context"
|
2021-11-29 14:38:45 +01:00
|
|
|
"encoding/json"
|
2023-11-18 16:25:37 +05:30
|
|
|
"fmt"
|
2022-03-03 19:44:29 +05:30
|
|
|
"net/http"
|
|
|
|
|
_ "net/http/pprof"
|
2020-04-04 15:59:05 +05:30
|
|
|
"os"
|
2023-12-20 14:29:20 +03:00
|
|
|
"path/filepath"
|
2023-01-31 22:08:17 +01:00
|
|
|
"reflect"
|
2020-04-04 15:59:05 +05:30
|
|
|
"strings"
|
2023-01-20 23:49:04 +05:30
|
|
|
"sync/atomic"
|
2021-04-16 16:56:41 +05:30
|
|
|
"time"
|
2020-04-04 15:59:05 +05:30
|
|
|
|
2023-11-18 16:25:37 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v3/internal/pdcp"
|
2023-10-30 19:02:06 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
|
2023-05-09 03:57:56 +05:30
|
|
|
uncoverlib "github.com/projectdiscovery/uncover"
|
2024-01-11 19:51:54 +05:30
|
|
|
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
|
2023-11-18 16:25:37 +05:30
|
|
|
"github.com/projectdiscovery/utils/env"
|
2023-12-20 14:29:20 +03:00
|
|
|
fileutil "github.com/projectdiscovery/utils/file"
|
2023-08-11 17:00:43 +03:00
|
|
|
permissionutil "github.com/projectdiscovery/utils/permission"
|
2023-04-19 21:58:48 +05:30
|
|
|
updateutils "github.com/projectdiscovery/utils/update"
|
2022-10-22 04:06:52 +05:30
|
|
|
|
2020-08-24 00:16:18 +05:30
|
|
|
"github.com/logrusorgru/aurora"
|
2021-07-07 19:15:09 +05:30
|
|
|
"github.com/pkg/errors"
|
2022-10-12 22:04:37 -05:00
|
|
|
"github.com/projectdiscovery/ratelimit"
|
2021-07-19 21:04:08 +03:00
|
|
|
|
2020-04-04 15:59:05 +05:30
|
|
|
"github.com/projectdiscovery/gologger"
|
2023-10-17 17:44:13 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v3/internal/colorizer"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/core"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/core/inputs/hybrid"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/external/customtemplates"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/input"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/parsers"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/projectfile"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/automaticscan"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hosterrorscache"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/uncover"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/excludematchers"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/reporting"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/utils/stats"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/utils/yaml"
|
2022-03-09 12:31:12 +01:00
|
|
|
"github.com/projectdiscovery/retryablehttp-go"
|
2023-06-12 12:30:46 +02:00
|
|
|
ptrutil "github.com/projectdiscovery/utils/ptr"
|
2020-04-04 15:59:05 +05:30
|
|
|
)
|
|
|
|
|
|
2023-11-18 16:25:37 +05:30
|
|
|
var (
|
|
|
|
|
// HideAutoSaveMsg is a global variable to hide the auto-save message
|
|
|
|
|
HideAutoSaveMsg = false
|
2023-11-20 21:19:19 +05:30
|
|
|
// EnableCloudUpload is global variable to enable cloud upload
|
|
|
|
|
EnableCloudUpload = false
|
2023-11-18 16:25:37 +05:30
|
|
|
)
|
|
|
|
|
|
2020-04-04 15:59:05 +05:30
|
|
|
// Runner is a client for running the enumeration process.
|
|
|
|
|
type Runner struct {
|
2021-10-27 15:53:04 +05:30
|
|
|
output output.Writer
|
|
|
|
|
interactsh *interactsh.Client
|
|
|
|
|
options *types.Options
|
|
|
|
|
projectFile *projectfile.ProjectFile
|
2022-08-10 23:35:58 +05:30
|
|
|
catalog catalog.Catalog
|
2021-10-27 15:53:04 +05:30
|
|
|
progress progress.Progress
|
|
|
|
|
colorizer aurora.Aurora
|
2023-02-07 09:45:49 +01:00
|
|
|
issuesClient reporting.Client
|
2021-10-28 17:20:07 +05:30
|
|
|
hmapInputProvider *hybrid.Input
|
2021-10-27 15:53:04 +05:30
|
|
|
browser *engine.Browser
|
2023-05-31 16:58:10 -04:00
|
|
|
rateLimiter *ratelimit.Limiter
|
2022-07-18 15:35:53 -05:00
|
|
|
hostErrors hosterrorscache.CacheInterface
|
2021-11-29 14:38:45 +01:00
|
|
|
resumeCfg *types.ResumeCfg
|
2022-03-03 19:44:29 +05:30
|
|
|
pprofServer *http.Server
|
2023-11-18 16:25:37 +05:30
|
|
|
// pdcp auto-save options
|
|
|
|
|
pdcpUploadErrMsg string
|
2020-04-04 15:59:05 +05:30
|
|
|
}
|
|
|
|
|
|
2022-03-03 19:44:29 +05:30
|
|
|
const pprofServerAddress = "127.0.0.1:8086"
|
|
|
|
|
|
2023-05-31 16:58:10 -04:00
|
|
|
// New creates a new client for running the enumeration process.
|
2020-12-29 15:38:14 +05:30
|
|
|
func New(options *types.Options) (*Runner, error) {
|
2020-04-04 15:59:05 +05:30
|
|
|
runner := &Runner{
|
2020-12-29 15:38:14 +05:30
|
|
|
options: options,
|
2020-04-04 15:59:05 +05:30
|
|
|
}
|
2022-06-21 21:10:10 +02:00
|
|
|
|
|
|
|
|
if options.HealthCheck {
|
|
|
|
|
gologger.Print().Msgf("%s\n", DoHealthCheck(options))
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 21:58:48 +05:30
|
|
|
// Version check by default
|
|
|
|
|
if config.DefaultConfig.CanCheckForUpdates() {
|
|
|
|
|
if err := installer.NucleiVersionCheck(); err != nil {
|
|
|
|
|
if options.Verbose || options.Debug {
|
|
|
|
|
gologger.Error().Msgf("nuclei version check failed got: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-19 17:42:52 -04:00
|
|
|
|
|
|
|
|
// check for custom template updates and update if available
|
|
|
|
|
ctm, err := customtemplates.NewCustomTemplatesManager(options)
|
|
|
|
|
if err != nil {
|
|
|
|
|
gologger.Error().Label("custom-templates").Msgf("Failed to create custom templates manager: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-31 16:58:10 -04:00
|
|
|
// Check for template updates and update if available.
|
|
|
|
|
// If the custom templates manager is not nil, we will install custom templates if there is a fresh installation
|
2023-07-17 15:23:10 -04:00
|
|
|
tm := &installer.TemplateManager{
|
|
|
|
|
CustomTemplates: ctm,
|
|
|
|
|
DisablePublicTemplates: options.PublicTemplateDisableDownload,
|
|
|
|
|
}
|
2023-04-19 21:58:48 +05:30
|
|
|
if err := tm.FreshInstallIfNotExists(); err != nil {
|
|
|
|
|
gologger.Warning().Msgf("failed to install nuclei templates: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
if err := tm.UpdateIfOutdated(); err != nil {
|
|
|
|
|
gologger.Warning().Msgf("failed to update nuclei templates: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if config.DefaultConfig.NeedsIgnoreFileUpdate() {
|
|
|
|
|
if err := installer.UpdateIgnoreFile(); err != nil {
|
|
|
|
|
gologger.Warning().Msgf("failed to update nuclei ignore file: %s\n", err)
|
|
|
|
|
}
|
2021-07-25 03:07:19 +05:30
|
|
|
}
|
2023-04-19 17:42:52 -04:00
|
|
|
|
|
|
|
|
if options.UpdateTemplates {
|
|
|
|
|
// we automatically check for updates unless explicitly disabled
|
|
|
|
|
// this print statement is only to inform the user that there are no updates
|
|
|
|
|
if !config.DefaultConfig.NeedsTemplateUpdate() {
|
|
|
|
|
gologger.Info().Msgf("No new updates found for nuclei templates")
|
|
|
|
|
}
|
|
|
|
|
// manually trigger update of custom templates
|
|
|
|
|
if ctm != nil {
|
|
|
|
|
ctm.Update(context.TODO())
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-25 03:07:19 +05:30
|
|
|
}
|
2023-04-19 21:58:48 +05:30
|
|
|
|
2021-08-31 19:53:53 +05:30
|
|
|
if options.Validate {
|
|
|
|
|
parsers.ShouldValidate = true
|
|
|
|
|
}
|
2022-12-28 14:46:34 +01:00
|
|
|
|
|
|
|
|
// TODO: refactor to pass options reference globally without cycles
|
2022-07-13 13:30:11 +02:00
|
|
|
parsers.NoStrictSyntax = options.NoStrictSyntax
|
2022-12-28 14:46:34 +01:00
|
|
|
yaml.StrictSyntax = !options.NoStrictSyntax
|
2022-11-03 20:27:18 +05:30
|
|
|
|
2021-07-25 03:13:46 +05:30
|
|
|
if options.Headless {
|
2021-12-05 20:14:16 +05:30
|
|
|
if engine.MustDisableSandbox() {
|
|
|
|
|
gologger.Warning().Msgf("The current platform and privileged user will run the browser without sandbox\n")
|
|
|
|
|
}
|
2021-07-25 03:13:46 +05:30
|
|
|
browser, err := engine.New(options)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
runner.browser = browser
|
|
|
|
|
}
|
2021-06-11 14:44:37 +05:30
|
|
|
|
2023-04-19 21:58:48 +05:30
|
|
|
runner.catalog = disk.NewCatalog(config.DefaultConfig.TemplatesDirectory)
|
2021-03-22 14:03:05 +05:30
|
|
|
|
2022-03-09 12:31:12 +01:00
|
|
|
var httpclient *retryablehttp.Client
|
|
|
|
|
if options.ProxyInternal && types.ProxyURL != "" || types.ProxySocksURL != "" {
|
|
|
|
|
var err error
|
|
|
|
|
httpclient, err = httpclientpool.Get(options, &httpclientpool.Configuration{})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-27 02:40:34 +05:30
|
|
|
if err := reporting.CreateConfigIfNotExists(); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-09-03 16:48:39 +03:00
|
|
|
reportingOptions, err := createReportingOptions(options)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2021-06-05 18:01:08 +05:30
|
|
|
}
|
2022-03-09 12:31:12 +01:00
|
|
|
if reportingOptions != nil && httpclient != nil {
|
|
|
|
|
reportingOptions.HttpClient = httpclient
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-22 14:03:05 +05:30
|
|
|
if reportingOptions != nil {
|
2021-07-07 19:23:25 +05:30
|
|
|
client, err := reporting.New(reportingOptions, options.ReportingDB)
|
|
|
|
|
if err != nil {
|
2021-07-07 19:15:09 +05:30
|
|
|
return nil, errors.Wrap(err, "could not create issue reporting client")
|
2021-02-02 12:10:47 +05:30
|
|
|
}
|
2021-07-07 19:23:25 +05:30
|
|
|
runner.issuesClient = client
|
2021-02-02 12:10:47 +05:30
|
|
|
}
|
2021-03-22 14:03:05 +05:30
|
|
|
|
2020-09-19 14:43:35 +02:00
|
|
|
// output coloring
|
|
|
|
|
useColor := !options.NoColor
|
2020-12-29 15:38:14 +05:30
|
|
|
runner.colorizer = aurora.NewAurora(useColor)
|
2022-03-14 12:32:05 +05:30
|
|
|
templates.Colorizer = runner.colorizer
|
|
|
|
|
templates.SeverityColorizer = colorizer.New(runner.colorizer)
|
2020-09-19 14:43:35 +02:00
|
|
|
|
2022-03-03 19:44:29 +05:30
|
|
|
if options.EnablePprof {
|
|
|
|
|
server := &http.Server{
|
|
|
|
|
Addr: pprofServerAddress,
|
|
|
|
|
Handler: http.DefaultServeMux,
|
|
|
|
|
}
|
|
|
|
|
gologger.Info().Msgf("Listening pprof debug server on: %s", pprofServerAddress)
|
|
|
|
|
runner.pprofServer = server
|
|
|
|
|
go func() {
|
2022-03-07 10:28:25 +05:30
|
|
|
_ = server.ListenAndServe()
|
2022-03-03 19:44:29 +05:30
|
|
|
}()
|
|
|
|
|
}
|
2020-08-28 11:17:37 +02:00
|
|
|
|
2023-11-18 16:25:37 +05:30
|
|
|
if (len(options.Templates) == 0 || !options.NewTemplates || (options.TargetsFilePath == "" && !options.Stdin && len(options.Targets) == 0)) && options.UpdateTemplates {
|
2020-06-25 03:53:37 +05:30
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
2020-04-26 06:48:10 +05:30
|
|
|
|
2021-10-27 15:53:04 +05:30
|
|
|
// Initialize the input source
|
2022-12-09 00:15:18 +05:30
|
|
|
hmapInput, err := hybrid.New(&hybrid.Options{
|
|
|
|
|
Options: options,
|
|
|
|
|
})
|
2021-10-27 15:53:04 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "could not create input provider")
|
2020-07-23 20:19:19 +02:00
|
|
|
}
|
2021-10-27 15:53:04 +05:30
|
|
|
runner.hmapInputProvider = hmapInput
|
2020-07-23 20:19:19 +02:00
|
|
|
|
2020-04-04 18:21:05 +05:30
|
|
|
// Create the output file if asked
|
2022-12-15 16:41:23 +01:00
|
|
|
outputWriter, err := output.NewStandardWriter(options)
|
2020-12-29 18:15:27 +05:30
|
|
|
if err != nil {
|
2021-07-07 19:15:09 +05:30
|
|
|
return nil, errors.Wrap(err, "could not create output file")
|
2020-04-04 18:21:05 +05:30
|
|
|
}
|
2023-11-18 16:25:37 +05:30
|
|
|
// setup a proxy writer to automatically upload results to PDCP
|
|
|
|
|
runner.output = runner.setupPDCPUpload(outputWriter)
|
2020-07-23 20:19:19 +02:00
|
|
|
|
2023-03-31 05:59:29 -04:00
|
|
|
if options.JSONL && options.EnableProgressBar {
|
2021-07-08 15:26:58 +05:30
|
|
|
options.StatsJSON = true
|
|
|
|
|
}
|
2021-07-08 18:50:03 +05:30
|
|
|
if options.StatsJSON {
|
|
|
|
|
options.EnableProgressBar = true
|
|
|
|
|
}
|
2020-07-31 23:07:33 +02:00
|
|
|
// Creates the progress tracking object
|
2020-12-17 20:33:42 +05:30
|
|
|
var progressErr error
|
2023-01-13 13:41:05 +05:30
|
|
|
statsInterval := options.StatsInterval
|
2023-11-18 16:25:37 +05:30
|
|
|
runner.progress, progressErr = progress.NewStatsTicker(statsInterval, options.EnableProgressBar, options.StatsJSON, false, options.MetricsPort)
|
2020-12-17 20:33:42 +05:30
|
|
|
if progressErr != nil {
|
|
|
|
|
return nil, progressErr
|
|
|
|
|
}
|
2020-07-23 20:19:19 +02:00
|
|
|
|
2021-09-01 17:34:51 +03:00
|
|
|
// create project file if requested or load the existing one
|
2020-10-17 02:10:47 +02:00
|
|
|
if options.Project {
|
2020-10-30 13:06:05 +01:00
|
|
|
var projectFileErr error
|
2021-08-03 14:51:34 +03:00
|
|
|
runner.projectFile, projectFileErr = projectfile.New(&projectfile.Options{Path: options.ProjectPath, Cleanup: utils.IsBlank(options.ProjectPath)})
|
2020-10-30 13:06:05 +01:00
|
|
|
if projectFileErr != nil {
|
|
|
|
|
return nil, projectFileErr
|
2020-10-15 23:39:00 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-29 14:38:45 +01:00
|
|
|
// create the resume configuration structure
|
|
|
|
|
resumeCfg := types.NewResumeCfg()
|
|
|
|
|
if runner.options.ShouldLoadResume() {
|
|
|
|
|
gologger.Info().Msg("Resuming from save checkpoint")
|
2022-02-25 13:04:46 +01:00
|
|
|
file, err := os.ReadFile(runner.options.Resume)
|
2021-11-29 14:38:45 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2023-05-31 16:58:10 -04:00
|
|
|
err = json.Unmarshal(file, &resumeCfg)
|
2021-11-29 14:38:45 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-12-16 22:32:03 +01:00
|
|
|
resumeCfg.Compile()
|
2021-11-29 14:38:45 +01:00
|
|
|
}
|
|
|
|
|
runner.resumeCfg = resumeCfg
|
|
|
|
|
|
2023-04-16 19:49:35 +02:00
|
|
|
opts := interactsh.DefaultOptions(runner.output, runner.issuesClient, runner.progress)
|
2021-11-16 20:02:39 +05:30
|
|
|
opts.Debug = runner.options.Debug
|
2022-02-25 23:11:56 +05:30
|
|
|
opts.NoColor = runner.options.NoColor
|
2022-01-13 13:22:43 +05:30
|
|
|
if options.InteractshURL != "" {
|
|
|
|
|
opts.ServerURL = options.InteractshURL
|
|
|
|
|
}
|
2021-11-16 20:02:39 +05:30
|
|
|
opts.Authorization = options.InteractshToken
|
2023-04-16 19:49:35 +02:00
|
|
|
opts.CacheSize = options.InteractionsCacheSize
|
2021-11-16 20:02:39 +05:30
|
|
|
opts.Eviction = time.Duration(options.InteractionsEviction) * time.Second
|
2022-03-09 12:31:12 +01:00
|
|
|
opts.CooldownPeriod = time.Duration(options.InteractionsCoolDownPeriod) * time.Second
|
2021-11-16 20:02:39 +05:30
|
|
|
opts.PollDuration = time.Duration(options.InteractionsPollDuration) * time.Second
|
|
|
|
|
opts.NoInteractsh = runner.options.NoInteractsh
|
2021-12-21 14:20:03 +05:30
|
|
|
opts.StopAtFirstMatch = runner.options.StopAtFirstMatch
|
2022-01-27 12:14:32 +05:30
|
|
|
opts.Debug = runner.options.Debug
|
|
|
|
|
opts.DebugRequest = runner.options.DebugRequests
|
|
|
|
|
opts.DebugResponse = runner.options.DebugResponse
|
2022-03-09 12:31:12 +01:00
|
|
|
if httpclient != nil {
|
|
|
|
|
opts.HTTPClient = httpclient
|
|
|
|
|
}
|
2023-08-18 01:01:16 +05:30
|
|
|
if opts.HTTPClient == nil {
|
|
|
|
|
httpOpts := retryablehttp.DefaultOptionsSingle
|
|
|
|
|
httpOpts.Timeout = 20 * time.Second // for stability reasons
|
|
|
|
|
if options.Timeout > 20 {
|
|
|
|
|
httpOpts.Timeout = time.Duration(options.Timeout) * time.Second
|
|
|
|
|
}
|
|
|
|
|
// in testing it was found most of times when interactsh failed, it was due to failure in registering /polling requests
|
|
|
|
|
opts.HTTPClient = retryablehttp.NewClient(retryablehttp.DefaultOptionsSingle)
|
|
|
|
|
}
|
2021-11-16 20:02:39 +05:30
|
|
|
interactshClient, err := interactsh.New(opts)
|
|
|
|
|
if err != nil {
|
|
|
|
|
gologger.Error().Msgf("Could not create interactsh client: %s", err)
|
|
|
|
|
} else {
|
|
|
|
|
runner.interactsh = interactshClient
|
2021-04-16 16:56:41 +05:30
|
|
|
}
|
|
|
|
|
|
2021-07-31 15:46:21 +05:30
|
|
|
if options.RateLimitMinute > 0 {
|
2023-05-31 16:58:10 -04:00
|
|
|
runner.rateLimiter = ratelimit.New(context.Background(), uint(options.RateLimitMinute), time.Minute)
|
2021-07-31 15:46:21 +05:30
|
|
|
} else if options.RateLimit > 0 {
|
2023-05-31 16:58:10 -04:00
|
|
|
runner.rateLimiter = ratelimit.New(context.Background(), uint(options.RateLimit), time.Second)
|
2020-11-16 00:40:32 +01:00
|
|
|
} else {
|
2023-05-31 16:58:10 -04:00
|
|
|
runner.rateLimiter = ratelimit.NewUnlimited(context.Background())
|
2020-11-16 00:40:32 +01:00
|
|
|
}
|
2020-04-04 15:59:05 +05:30
|
|
|
return runner, nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-18 16:25:37 +05:30
|
|
|
// runStandardEnumeration runs standard enumeration
|
|
|
|
|
func (r *Runner) runStandardEnumeration(executerOpts protocols.ExecutorOptions, store *loader.Store, engine *core.Engine) (*atomic.Bool, error) {
|
|
|
|
|
if r.options.AutomaticScan {
|
|
|
|
|
return r.executeSmartWorkflowInput(executerOpts, store, engine)
|
2021-09-03 16:48:39 +03:00
|
|
|
}
|
2023-11-18 16:25:37 +05:30
|
|
|
return r.executeTemplatesInput(store, engine)
|
2021-09-03 16:48:39 +03:00
|
|
|
}
|
|
|
|
|
|
2020-04-04 15:59:05 +05:30
|
|
|
// Close releases all the resources and cleans up
|
2020-04-04 18:21:05 +05:30
|
|
|
func (r *Runner) Close() {
|
2020-09-11 21:35:29 +05:30
|
|
|
if r.output != nil {
|
|
|
|
|
r.output.Close()
|
|
|
|
|
}
|
2024-01-13 00:44:25 +05:30
|
|
|
if r.issuesClient != nil {
|
|
|
|
|
r.issuesClient.Close()
|
|
|
|
|
}
|
2020-12-29 15:38:14 +05:30
|
|
|
if r.projectFile != nil {
|
|
|
|
|
r.projectFile.Close()
|
2020-10-15 23:39:00 +02:00
|
|
|
}
|
2021-10-27 15:53:04 +05:30
|
|
|
r.hmapInputProvider.Close()
|
2021-04-18 11:57:43 +02:00
|
|
|
protocolinit.Close()
|
2022-03-03 19:44:29 +05:30
|
|
|
if r.pprofServer != nil {
|
|
|
|
|
_ = r.pprofServer.Shutdown(context.Background())
|
|
|
|
|
}
|
2023-05-31 16:58:10 -04:00
|
|
|
if r.rateLimiter != nil {
|
|
|
|
|
r.rateLimiter.Stop()
|
2022-12-24 14:52:14 +01:00
|
|
|
}
|
2024-01-13 00:44:25 +05:30
|
|
|
r.progress.Stop()
|
|
|
|
|
if r.browser != nil {
|
|
|
|
|
r.browser.Close()
|
|
|
|
|
}
|
2020-04-04 18:21:05 +05:30
|
|
|
}
|
2020-04-04 15:59:05 +05:30
|
|
|
|
2023-11-18 16:25:37 +05:30
|
|
|
// setupPDCPUpload sets up the PDCP upload writer
|
|
|
|
|
// by creating a new writer and returning it
|
|
|
|
|
func (r *Runner) setupPDCPUpload(writer output.Writer) output.Writer {
|
2024-01-21 02:26:16 +05:30
|
|
|
// if scanid is given implicitly consider that scan upload is enabled
|
|
|
|
|
if r.options.ScanID != "" {
|
|
|
|
|
r.options.EnableCloudUpload = true
|
|
|
|
|
}
|
2023-11-20 21:19:19 +05:30
|
|
|
if !(r.options.EnableCloudUpload || EnableCloudUpload) {
|
2023-11-18 16:25:37 +05:30
|
|
|
r.pdcpUploadErrMsg = fmt.Sprintf("[%v] Scan results upload to cloud is disabled.", aurora.BrightYellow("WRN"))
|
|
|
|
|
return writer
|
|
|
|
|
}
|
|
|
|
|
color := aurora.NewAurora(!r.options.NoColor)
|
2024-01-11 19:51:54 +05:30
|
|
|
h := &pdcpauth.PDCPCredHandler{}
|
2023-11-18 16:25:37 +05:30
|
|
|
creds, err := h.GetCreds()
|
|
|
|
|
if err != nil {
|
2024-01-11 19:51:54 +05:30
|
|
|
if err != pdcpauth.ErrNoCreds && !HideAutoSaveMsg {
|
2023-11-18 16:25:37 +05:30
|
|
|
gologger.Verbose().Msgf("Could not get credentials for cloud upload: %s\n", err)
|
|
|
|
|
}
|
2024-01-11 19:51:54 +05:30
|
|
|
r.pdcpUploadErrMsg = fmt.Sprintf("[%v] To view results on Cloud Dashboard, Configure API key from %v", color.BrightYellow("WRN"), pdcpauth.DashBoardURL)
|
2023-11-18 16:25:37 +05:30
|
|
|
return writer
|
|
|
|
|
}
|
2024-01-21 02:26:16 +05:30
|
|
|
uploadWriter, err := pdcp.NewUploadWriter(context.Background(), creds)
|
2023-11-18 16:25:37 +05:30
|
|
|
if err != nil {
|
2024-01-11 19:51:54 +05:30
|
|
|
r.pdcpUploadErrMsg = fmt.Sprintf("[%v] PDCP (%v) Auto-Save Failed: %s\n", color.BrightYellow("WRN"), pdcpauth.DashBoardURL, err)
|
2023-11-18 16:25:37 +05:30
|
|
|
return writer
|
|
|
|
|
}
|
2024-01-21 02:26:16 +05:30
|
|
|
if r.options.ScanID != "" {
|
|
|
|
|
uploadWriter.SetScanID(r.options.ScanID)
|
|
|
|
|
}
|
2023-11-18 16:25:37 +05:30
|
|
|
return output.NewMultiWriter(writer, uploadWriter)
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-02 13:49:16 +02:00
|
|
|
// RunEnumeration sets up the input layer for giving input nuclei.
|
|
|
|
|
// binary and runs the actual enumeration
|
2021-07-07 19:15:09 +05:30
|
|
|
func (r *Runner) RunEnumeration() error {
|
2021-09-01 17:34:51 +03:00
|
|
|
// If user asked for new templates to be executed, collect the list from the templates' directory.
|
2021-03-05 12:08:31 +05:30
|
|
|
if r.options.NewTemplates {
|
2023-04-19 21:58:48 +05:30
|
|
|
if arr := config.DefaultConfig.GetNewAdditions(); len(arr) > 0 {
|
|
|
|
|
r.options.Templates = append(r.options.Templates, arr...)
|
2021-03-05 12:08:31 +05:30
|
|
|
}
|
|
|
|
|
}
|
2022-07-13 06:19:06 -05:00
|
|
|
if len(r.options.NewTemplatesWithVersion) > 0 {
|
2023-04-19 21:58:48 +05:30
|
|
|
if arr := installer.GetNewTemplatesInVersions(r.options.NewTemplatesWithVersion...); len(arr) > 0 {
|
|
|
|
|
r.options.Templates = append(r.options.Templates, arr...)
|
2022-07-13 06:19:06 -05:00
|
|
|
}
|
|
|
|
|
}
|
2021-12-01 10:35:18 -06:00
|
|
|
// Exclude ignored file for validation
|
|
|
|
|
if !r.options.Validate {
|
|
|
|
|
ignoreFile := config.ReadIgnoreFile()
|
|
|
|
|
r.options.ExcludeTags = append(r.options.ExcludeTags, ignoreFile.Tags...)
|
|
|
|
|
r.options.ExcludedTemplates = append(r.options.ExcludedTemplates, ignoreFile.Files...)
|
|
|
|
|
}
|
2021-10-27 16:50:36 +05:30
|
|
|
|
2023-05-31 16:58:10 -04:00
|
|
|
// Create the executor options which will be used throughout the execution
|
2021-10-27 16:50:36 +05:30
|
|
|
// stage by the nuclei engine modules.
|
2023-05-31 16:58:10 -04:00
|
|
|
executorOpts := protocols.ExecutorOptions{
|
2021-08-16 21:24:37 +05:30
|
|
|
Output: r.output,
|
|
|
|
|
Options: r.options,
|
|
|
|
|
Progress: r.progress,
|
|
|
|
|
Catalog: r.catalog,
|
|
|
|
|
IssuesClient: r.issuesClient,
|
2023-05-31 16:58:10 -04:00
|
|
|
RateLimiter: r.rateLimiter,
|
2021-08-16 21:24:37 +05:30
|
|
|
Interactsh: r.interactsh,
|
|
|
|
|
ProjectFile: r.projectFile,
|
|
|
|
|
Browser: r.browser,
|
2021-10-28 17:20:07 +05:30
|
|
|
Colorizer: r.colorizer,
|
2021-11-29 14:38:45 +01:00
|
|
|
ResumeCfg: r.resumeCfg,
|
2022-06-24 23:09:27 +05:30
|
|
|
ExcludeMatchers: excludematchers.New(r.options.ExcludeMatchers),
|
2022-10-20 17:23:00 +05:30
|
|
|
InputHelper: input.NewHelper(),
|
2021-07-01 14:36:40 +05:30
|
|
|
}
|
2023-01-22 10:38:50 +01:00
|
|
|
|
|
|
|
|
if r.options.ShouldUseHostError() {
|
2023-03-14 01:29:42 -07:00
|
|
|
cache := hosterrorscache.New(r.options.MaxHostError, hosterrorscache.DefaultMaxHostsCount, r.options.TrackError)
|
2023-01-22 10:38:50 +01:00
|
|
|
cache.SetVerbose(r.options.Verbose)
|
|
|
|
|
r.hostErrors = cache
|
2023-05-31 16:58:10 -04:00
|
|
|
executorOpts.HostErrorsCache = cache
|
2023-01-22 10:38:50 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-31 16:58:10 -04:00
|
|
|
executorEngine := core.New(r.options)
|
|
|
|
|
executorEngine.SetExecuterOptions(executorOpts)
|
2021-07-15 13:41:41 +03:00
|
|
|
|
2023-05-31 16:58:10 -04:00
|
|
|
workflowLoader, err := parsers.NewLoader(&executorOpts)
|
2021-07-15 13:41:41 +03:00
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "Could not create loader.")
|
|
|
|
|
}
|
2023-05-31 16:58:10 -04:00
|
|
|
executorOpts.WorkflowLoader = workflowLoader
|
2021-07-15 13:41:41 +03:00
|
|
|
|
2023-05-31 16:58:10 -04:00
|
|
|
store, err := loader.New(loader.NewConfig(r.options, r.catalog, executorOpts))
|
2021-06-30 18:39:01 +05:30
|
|
|
if err != nil {
|
2021-07-07 19:15:09 +05:30
|
|
|
return errors.Wrap(err, "could not load templates from config")
|
2020-08-02 15:48:10 +02:00
|
|
|
}
|
2022-11-15 01:37:00 +05:30
|
|
|
|
2021-07-07 19:03:14 +05:30
|
|
|
if r.options.Validate {
|
2022-05-25 11:26:05 +05:30
|
|
|
if err := store.ValidateTemplates(); err != nil {
|
2021-08-27 17:06:06 +03:00
|
|
|
return err
|
2021-07-07 19:03:14 +05:30
|
|
|
}
|
2021-12-05 15:11:14 +01:00
|
|
|
if stats.GetValue(parsers.SyntaxErrorStats) == 0 && stats.GetValue(parsers.SyntaxWarningStats) == 0 && stats.GetValue(parsers.RuntimeWarningsStats) == 0 {
|
2021-08-31 19:27:26 +05:30
|
|
|
gologger.Info().Msgf("All templates validated successfully\n")
|
|
|
|
|
} else {
|
|
|
|
|
return errors.New("encountered errors while performing template validation")
|
|
|
|
|
}
|
2021-07-07 19:23:25 +05:30
|
|
|
return nil // exit
|
2021-07-07 19:03:14 +05:30
|
|
|
}
|
2022-05-25 11:26:05 +05:30
|
|
|
store.Load()
|
2023-06-09 02:28:40 +08:00
|
|
|
// TODO: remove below functions after v3 or update warning messages
|
2023-05-04 01:43:41 +05:30
|
|
|
disk.PrintDeprecatedPathsMsgIfApplicable(r.options.Silent)
|
|
|
|
|
templates.PrintDeprecatedProtocolNameMsgIfApplicable(r.options.Silent, r.options.Verbose)
|
2021-08-31 19:27:26 +05:30
|
|
|
|
2022-11-16 11:12:39 +05:30
|
|
|
// add the hosts from the metadata queries of loaded templates into input provider
|
|
|
|
|
if r.options.Uncover && len(r.options.UncoverQuery) == 0 {
|
2023-05-09 03:57:56 +05:30
|
|
|
uncoverOpts := &uncoverlib.Options{
|
|
|
|
|
Limit: r.options.UncoverLimit,
|
|
|
|
|
MaxRetry: r.options.Retries,
|
|
|
|
|
Timeout: r.options.Timeout,
|
|
|
|
|
RateLimit: uint(r.options.UncoverRateLimit),
|
|
|
|
|
RateLimitUnit: time.Minute, // default unit is minute
|
|
|
|
|
}
|
|
|
|
|
ret := uncover.GetUncoverTargetsFromMetadata(context.TODO(), store.Templates(), r.options.UncoverField, uncoverOpts)
|
2022-11-16 11:12:39 +05:30
|
|
|
for host := range ret {
|
2023-11-23 19:35:20 +01:00
|
|
|
r.hmapInputProvider.SetWithExclusions(host)
|
2022-11-16 11:12:39 +05:30
|
|
|
}
|
|
|
|
|
}
|
2022-09-20 16:33:57 -05:00
|
|
|
// list all templates
|
2022-11-29 13:18:44 +01:00
|
|
|
if r.options.TemplateList || r.options.TemplateDisplay {
|
2022-09-20 16:33:57 -05:00
|
|
|
r.listAvailableStoreTemplates(store)
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
2023-04-19 21:58:48 +05:30
|
|
|
|
|
|
|
|
// display execution info like version , templates used etc
|
2021-10-28 23:17:05 +05:30
|
|
|
r.displayExecutionInfo(store)
|
2020-08-02 13:49:16 +02:00
|
|
|
|
2022-10-20 17:23:00 +05:30
|
|
|
// If not explicitly disabled, check if http based protocols
|
2023-05-31 16:58:10 -04:00
|
|
|
// are used, and if inputs are non-http to pre-perform probing
|
2022-10-20 17:23:00 +05:30
|
|
|
// of urls and storing them for execution.
|
|
|
|
|
if !r.options.DisableHTTPProbe && loader.IsHTTPBasedProtocolUsed(store) && r.isInputNonHTTP() {
|
|
|
|
|
inputHelpers, err := r.initializeTemplatesHTTPInput()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not probe http input")
|
|
|
|
|
}
|
2023-05-31 16:58:10 -04:00
|
|
|
executorOpts.InputHelper.InputsHTTP = inputHelpers
|
2022-10-20 17:23:00 +05:30
|
|
|
}
|
2022-04-18 17:21:33 -05:00
|
|
|
|
2022-10-22 04:06:52 +05:30
|
|
|
enumeration := false
|
2022-10-20 17:23:00 +05:30
|
|
|
var results *atomic.Bool
|
2023-11-18 16:25:37 +05:30
|
|
|
results, err = r.runStandardEnumeration(executorOpts, store, executorEngine)
|
|
|
|
|
enumeration = true
|
2022-10-22 04:06:52 +05:30
|
|
|
|
|
|
|
|
if !enumeration {
|
|
|
|
|
return err
|
2022-01-18 20:59:37 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r.interactsh != nil {
|
|
|
|
|
matched := r.interactsh.Close()
|
|
|
|
|
if matched {
|
2022-09-19 08:38:52 +02:00
|
|
|
results.CompareAndSwap(false, true)
|
2022-01-18 20:59:37 +05:30
|
|
|
}
|
|
|
|
|
}
|
2023-05-31 16:58:10 -04:00
|
|
|
if executorOpts.InputHelper != nil {
|
|
|
|
|
_ = executorOpts.InputHelper.Close()
|
2022-10-20 17:23:00 +05:30
|
|
|
}
|
2022-03-21 11:33:10 +01:00
|
|
|
|
2023-06-12 12:35:21 +02:00
|
|
|
// todo: error propagation without canonical straight error check is required by cloud?
|
|
|
|
|
// use safe dereferencing to avoid potential panics in case of previous unchecked errors
|
2023-06-12 12:30:46 +02:00
|
|
|
if v := ptrutil.Safe(results); !v.Load() {
|
2022-01-18 20:59:37 +05:30
|
|
|
gologger.Info().Msgf("No results found. Better luck next time!")
|
|
|
|
|
}
|
2023-05-31 16:58:10 -04:00
|
|
|
// check if a passive scan was requested but no target was provided
|
2023-02-07 00:40:38 +01:00
|
|
|
if r.options.OfflineHTTP && len(r.options.Targets) == 0 && r.options.TargetsFilePath == "" {
|
|
|
|
|
return errors.Wrap(err, "missing required input (http response) to run passive templates")
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-18 20:59:37 +05:30
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-20 17:23:00 +05:30
|
|
|
func (r *Runner) isInputNonHTTP() bool {
|
|
|
|
|
var nonURLInput bool
|
2022-11-09 14:18:56 +01:00
|
|
|
r.hmapInputProvider.Scan(func(value *contextargs.MetaInput) bool {
|
|
|
|
|
if !strings.Contains(value.Input, "://") {
|
2022-10-20 17:23:00 +05:30
|
|
|
nonURLInput = true
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
})
|
|
|
|
|
return nonURLInput
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-31 16:58:10 -04:00
|
|
|
func (r *Runner) executeSmartWorkflowInput(executorOpts protocols.ExecutorOptions, store *loader.Store, engine *core.Engine) (*atomic.Bool, error) {
|
2022-03-14 16:25:27 +05:30
|
|
|
r.progress.Init(r.hmapInputProvider.Count(), 0, 0)
|
|
|
|
|
|
2022-03-14 12:32:05 +05:30
|
|
|
service, err := automaticscan.New(automaticscan.Options{
|
2023-05-31 16:58:10 -04:00
|
|
|
ExecuterOpts: executorOpts,
|
2022-01-18 20:59:37 +05:30
|
|
|
Store: store,
|
|
|
|
|
Engine: engine,
|
|
|
|
|
Target: r.hmapInputProvider,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
2022-04-19 16:14:49 +05:30
|
|
|
return nil, errors.Wrap(err, "could not create automatic scan service")
|
2022-01-18 20:59:37 +05:30
|
|
|
}
|
2024-02-01 15:19:20 +08:00
|
|
|
if err := service.Execute(); err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "could not execute automatic scan")
|
|
|
|
|
}
|
2022-01-18 20:59:37 +05:30
|
|
|
result := &atomic.Bool{}
|
|
|
|
|
result.Store(service.Close())
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) executeTemplatesInput(store *loader.Store, engine *core.Engine) (*atomic.Bool, error) {
|
2021-07-01 18:22:08 +05:30
|
|
|
if r.options.VerboseVerbose {
|
2021-07-01 14:36:40 +05:30
|
|
|
for _, template := range store.Templates() {
|
|
|
|
|
r.logAvailableTemplate(template.Path)
|
|
|
|
|
}
|
|
|
|
|
for _, template := range store.Workflows() {
|
|
|
|
|
r.logAvailableTemplate(template.Path)
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-15 14:17:34 +05:30
|
|
|
|
2023-09-02 14:34:05 +05:30
|
|
|
finalTemplates := []*templates.Template{}
|
|
|
|
|
finalTemplates = append(finalTemplates, store.Templates()...)
|
2021-10-28 17:20:07 +05:30
|
|
|
finalTemplates = append(finalTemplates, store.Workflows()...)
|
|
|
|
|
|
2023-09-02 14:34:05 +05:30
|
|
|
if len(finalTemplates) == 0 {
|
|
|
|
|
return nil, errors.New("no templates provided for scan")
|
2020-04-04 15:59:05 +05:30
|
|
|
}
|
2020-06-27 20:50:43 +05:30
|
|
|
|
2023-09-02 14:34:05 +05:30
|
|
|
results := engine.ExecuteScanWithOpts(finalTemplates, r.hmapInputProvider, r.options.DisableClustering)
|
2022-01-18 20:59:37 +05:30
|
|
|
return results, nil
|
2020-04-04 15:59:05 +05:30
|
|
|
}
|
2021-03-05 12:08:31 +05:30
|
|
|
|
2021-10-28 23:17:05 +05:30
|
|
|
// displayExecutionInfo displays misc info about the nuclei engine execution
|
|
|
|
|
func (r *Runner) displayExecutionInfo(store *loader.Store) {
|
|
|
|
|
// Display stats for any loaded templates' syntax warnings or errors
|
|
|
|
|
stats.Display(parsers.SyntaxWarningStats)
|
|
|
|
|
stats.Display(parsers.SyntaxErrorStats)
|
2021-12-05 15:11:14 +01:00
|
|
|
stats.Display(parsers.RuntimeWarningsStats)
|
2023-10-16 14:34:52 +05:30
|
|
|
if r.options.Verbose {
|
|
|
|
|
// only print these stats in verbose mode
|
|
|
|
|
stats.DisplayAsWarning(parsers.HeadlessFlagWarningStats)
|
2023-11-16 17:56:07 +05:30
|
|
|
stats.DisplayAsWarning(parsers.CodeFlagWarningStats)
|
2023-10-16 14:34:52 +05:30
|
|
|
stats.DisplayAsWarning(parsers.TemplatesExecutedStats)
|
|
|
|
|
}
|
|
|
|
|
stats.DisplayAsWarning(parsers.UnsignedWarning)
|
2021-10-28 23:17:05 +05:30
|
|
|
|
2023-04-19 21:58:48 +05:30
|
|
|
cfg := config.DefaultConfig
|
2021-10-28 23:17:05 +05:30
|
|
|
|
2023-04-19 21:58:48 +05:30
|
|
|
gologger.Info().Msgf("Current nuclei version: %v %v", config.Version, updateutils.GetVersionDescription(config.Version, cfg.LatestNucleiVersion))
|
|
|
|
|
gologger.Info().Msgf("Current nuclei-templates version: %v %v", cfg.TemplateVersion, updateutils.GetVersionDescription(cfg.TemplateVersion, cfg.LatestNucleiTemplatesVersion))
|
2023-11-18 16:25:37 +05:30
|
|
|
if !HideAutoSaveMsg {
|
|
|
|
|
if r.pdcpUploadErrMsg != "" {
|
|
|
|
|
gologger.Print().Msgf("%s", r.pdcpUploadErrMsg)
|
|
|
|
|
} else {
|
2024-01-11 19:51:54 +05:30
|
|
|
gologger.Info().Msgf("To view results on cloud dashboard, visit %v/scans upon scan completion.", pdcpauth.DashBoardURL)
|
2023-11-18 16:25:37 +05:30
|
|
|
}
|
|
|
|
|
}
|
2021-10-28 23:17:05 +05:30
|
|
|
|
|
|
|
|
if len(store.Templates()) > 0 {
|
2023-04-19 21:58:48 +05:30
|
|
|
gologger.Info().Msgf("New templates added in latest release: %d", len(config.DefaultConfig.GetNewAdditions()))
|
|
|
|
|
gologger.Info().Msgf("Templates loaded for current scan: %d", len(store.Templates()))
|
2021-10-28 23:17:05 +05:30
|
|
|
}
|
|
|
|
|
if len(store.Workflows()) > 0 {
|
2023-04-19 21:58:48 +05:30
|
|
|
gologger.Info().Msgf("Workflows loaded for current scan: %d", len(store.Workflows()))
|
2021-10-28 23:17:05 +05:30
|
|
|
}
|
2023-10-13 13:17:27 +05:30
|
|
|
for k, v := range templates.SignatureStats {
|
|
|
|
|
if v.Load() > 0 {
|
|
|
|
|
if k != templates.Unsigned {
|
|
|
|
|
gologger.Info().Msgf("Executing %d signed templates from %s", v.Load(), k)
|
2023-10-17 17:44:13 +05:30
|
|
|
} else if !r.options.Silent && !config.DefaultConfig.HideTemplateSigWarning {
|
2023-11-02 13:33:40 +05:30
|
|
|
gologger.Print().Msgf("[%v] Executing %d unsigned templates. Use with caution.", aurora.BrightYellow("WRN"), v.Load())
|
2023-10-13 13:17:27 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-09 14:55:51 +05:30
|
|
|
if r.hmapInputProvider.Count() > 0 {
|
2023-04-19 21:58:48 +05:30
|
|
|
gologger.Info().Msgf("Targets loaded for current scan: %d", r.hmapInputProvider.Count())
|
2021-03-05 12:08:31 +05:30
|
|
|
}
|
2022-01-14 11:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2021-11-29 14:38:45 +01:00
|
|
|
// SaveResumeConfig to file
|
2022-02-24 14:32:41 +05:30
|
|
|
func (r *Runner) SaveResumeConfig(path string) error {
|
2023-12-20 14:29:20 +03:00
|
|
|
dir := filepath.Dir(path)
|
|
|
|
|
if !fileutil.FolderExists(dir) {
|
|
|
|
|
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-26 15:00:15 +02:00
|
|
|
resumeCfgClone := r.resumeCfg.Clone()
|
|
|
|
|
resumeCfgClone.ResumeFrom = resumeCfgClone.Current
|
|
|
|
|
data, _ := json.MarshalIndent(resumeCfgClone, "", "\t")
|
2021-11-29 14:38:45 +01:00
|
|
|
|
2023-08-11 17:00:43 +03:00
|
|
|
return os.WriteFile(path, data, permissionutil.ConfigFilePermission)
|
2021-11-29 14:38:45 +01:00
|
|
|
}
|
2023-01-31 22:08:17 +01:00
|
|
|
|
|
|
|
|
type WalkFunc func(reflect.Value, reflect.StructField)
|
|
|
|
|
|
|
|
|
|
// Walk traverses a struct and executes a callback function on each value in the struct.
|
|
|
|
|
// The interface{} passed to the function should be a pointer to a struct or a struct.
|
|
|
|
|
// WalkFunc is the callback function used for each value in the struct. It is passed the
|
2023-05-31 16:58:10 -04:00
|
|
|
// reflect.Value and reflect.Type properties of the value in the struct.
|
2023-01-31 22:08:17 +01:00
|
|
|
func Walk(s interface{}, callback WalkFunc) {
|
|
|
|
|
structValue := reflect.ValueOf(s)
|
|
|
|
|
if structValue.Kind() == reflect.Ptr {
|
|
|
|
|
structValue = structValue.Elem()
|
|
|
|
|
}
|
|
|
|
|
if structValue.Kind() != reflect.Struct {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < structValue.NumField(); i++ {
|
|
|
|
|
field := structValue.Field(i)
|
|
|
|
|
fieldType := structValue.Type().Field(i)
|
|
|
|
|
if !fieldType.IsExported() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if field.Kind() == reflect.Struct {
|
|
|
|
|
Walk(field.Addr().Interface(), callback)
|
|
|
|
|
} else if field.Kind() == reflect.Ptr && field.Elem().Kind() == reflect.Struct {
|
|
|
|
|
Walk(field.Interface(), callback)
|
|
|
|
|
} else {
|
|
|
|
|
callback(field, fieldType)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// expandEndVars looks for values in a struct tagged with "yaml" and checks if they are prefixed with '$'.
|
|
|
|
|
// If they are, it will try to retrieve the value from the environment and if it exists, it will set the
|
|
|
|
|
// value of the field to that of the environment variable.
|
|
|
|
|
func expandEndVars(f reflect.Value, fieldType reflect.StructField) {
|
|
|
|
|
if _, ok := fieldType.Tag.Lookup("yaml"); !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if f.Kind() == reflect.String {
|
|
|
|
|
str := f.String()
|
|
|
|
|
if strings.HasPrefix(str, "$") {
|
|
|
|
|
env := strings.TrimPrefix(str, "$")
|
|
|
|
|
retrievedEnv := os.Getenv(env)
|
|
|
|
|
if retrievedEnv != "" {
|
|
|
|
|
f.SetString(os.Getenv(env))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-18 16:25:37 +05:30
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
HideAutoSaveMsg = env.GetEnvOrDefault("DISABLE_CLOUD_UPLOAD_WRN", false)
|
2023-11-20 21:19:19 +05:30
|
|
|
EnableCloudUpload = env.GetEnvOrDefault("ENABLE_CLOUD_UPLOAD", false)
|
2023-11-18 16:25:37 +05:30
|
|
|
}
|