dddd/common/callnuclei/callnuclei.go

599 lines
18 KiB
Go
Raw Normal View History

2023-08-18 08:55:46 +02:00
package callnuclei
import (
"fmt"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"os"
"os/signal"
"runtime"
"runtime/pprof"
"time"
"github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/gologger/levels"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/exportrunner"
"github.com/projectdiscovery/nuclei/v2/pkg/operators/common/dsl"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils/monitor"
errorutil "github.com/projectdiscovery/utils/errors"
fileutil "github.com/projectdiscovery/utils/file"
)
var (
cfgFile string
memProfile string // optional profile file path
options = &types.Options{}
)
2023-09-13 04:36:42 +02:00
func CallNuclei(TargetAndPocsName map[string][]string,
proxy string,
callBack func(result output.ResultEvent),
nameForSearch string) []output.ResultEvent {
2023-08-18 08:55:46 +02:00
// 设置结果回调
output.AddResultCallback = callBack
if err := exportrunner.ExportRunnerConfigureOptions(); err != nil {
gologger.Fatal().Msgf("Could not initialize options: %s\n", err)
}
2023-09-13 04:36:42 +02:00
readConfig(TargetAndPocsName, proxy, nameForSearch)
2023-08-18 08:55:46 +02:00
// configPath, _ := flagSet.GetConfigFilePath()
if options.ListDslSignatures {
gologger.Info().Msgf("The available custom DSL functions are:")
fmt.Println(dsl.GetPrintableDslFunctionSignatures(options.NoColor))
return []output.ResultEvent{}
}
// Profiling related code
if memProfile != "" {
f, err := os.Create(memProfile)
if err != nil {
gologger.Fatal().Msgf("profile: could not create memory profile %q: %v", memProfile, err)
}
old := runtime.MemProfileRate
runtime.MemProfileRate = 4096
gologger.Print().Msgf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, memProfile)
defer func() {
_ = pprof.Lookup("heap").WriteTo(f, 0)
f.Close()
runtime.MemProfileRate = old
gologger.Print().Msgf("profile: memory profiling disabled, %s", memProfile)
}()
}
exportrunner.ExportRunnerParseOptions(options)
if options.HangMonitor {
cancel := monitor.NewStackMonitor(10 * time.Second)
defer cancel()
}
nucleiRunner, err := exportrunner.ExportRunnerNew(options)
if err != nil {
gologger.Fatal().Msgf("Could not create runner: %s\n", err)
}
if nucleiRunner == nil {
return []output.ResultEvent{}
}
// Setup graceful exits
resumeFileName := types.DefaultResumeFilePath()
c := make(chan os.Signal, 1)
defer close(c)
signal.Notify(c, os.Interrupt)
go func() {
for range c {
gologger.Info().Msgf("CTRL+C pressed: Exiting\n")
nucleiRunner.Close()
if options.ShouldSaveResume() {
gologger.Info().Msgf("Creating resume file: %s\n", resumeFileName)
err := nucleiRunner.SaveResumeConfig(resumeFileName)
if err != nil {
gologger.Error().Msgf("Couldn't create resume file: %s\n", err)
}
}
os.Exit(1)
}
}()
if err := nucleiRunner.RunEnumeration(TargetAndPocsName); err != nil {
if options.Validate {
gologger.Fatal().Msgf("Could not validate templates: %s\n", err)
} else {
gologger.Fatal().Msgf("Could not run nuclei: %s\n", err)
}
}
nucleiRunner.Close()
// on successful execution remove the resume file in case it exists
if fileutil.FileExists(resumeFileName) {
os.Remove(resumeFileName)
}
return output.Results
}
2023-09-13 04:36:42 +02:00
func readConfig(TargetAndPocsName map[string][]string, proxy string, nameForSearch string) {
2023-08-18 08:55:46 +02:00
pwd, _ := os.Getwd()
// target URLs/hosts to scan
// 扫描目标
var targets []string
for k, _ := range TargetAndPocsName {
targets = append(targets, k)
}
options.Targets = targets
// path to file containing a list of target URLs/hosts to scan (one per line)
// 包含要扫描的目标URL/主机列表的文件路径(每行一个)
options.TargetsFilePath = ""
// resume scan using resume.cfg (clustering will be disabled)
// 使用resume.cfg恢复扫描(将禁用群集)
options.Resume = ""
// scan all the IP's associated with dns record
// 扫描与DNS记录相关联的所有IP
options.ScanAllIPs = false
// IP version to scan of hostname (4,6) - (default 4)
// 要扫描主机名的IP版本(46)-(默认为4)
options.IPVersion = nil
// run only new templates added in latest nuclei-templates release
// 仅运行在最新版本的nuclei-templates中添加的新模板
options.NewTemplates = false
// run new templates added in specific version
// 运行指定版本添加的模板
options.NewTemplatesWithVersion = nil
// automatic web scan using wappalyzer technology detection to tags mapping
// 使用wappalyzer技术检测tags自动web扫描
// 这里被魔改了,根据提供的目标与Pocs的映射进行自动扫描
2023-09-16 17:58:50 +02:00
// 必须设置为true
2023-08-18 08:55:46 +02:00
options.AutomaticScan = true
// list of template or template directory to run (comma-separated, file)
2023-09-16 17:58:50 +02:00
// 要运行的模板或模板目录列表(逗号分隔,文件) -t 指定的模板目录
// 不嵌入可执行文件是为了方便增删poc。内网版本嵌入
2023-08-18 08:55:46 +02:00
options.Templates = []string{pwd + "/config/pocs/"}
// list of template urls to run (comma-separated, file)
// 要运行的模板url列表(逗号分隔,文件)
options.TemplateURLs = nil
// list of workflow or workflow directory to run (comma-separated, file)
// 要运行的工作流或工作流目录列表(逗号分隔,文件) -w 指定
options.Workflows = nil
// list of workflow urls to run (comma-separated, file)
// 要运行的工作流URL列表(逗号分隔,文件)
options.WorkflowURLs = nil
// validate the passed templates to nuclei
// 验证通过的模板
options.Validate = false
// disable strict syntax check on templates
// 禁用模板的严格检查
options.NoStrictSyntax = false
// displays the templates content
// 显示模板内容
options.TemplateDisplay = false
// list all available templates
// 列出所有可用的模板
options.TemplateList = false
// allowed domain list to load remote templates from
// 允许域列表从以下位置加载远程模板
2023-09-16 17:58:50 +02:00
options.RemoteTemplateDomainList = []string{"templates.nuclei.sh"}
2023-08-18 08:55:46 +02:00
// templates to run based on authors (comma-separated, file)
// 执行指定作者的模板(逗号分隔,文件)
options.Authors = nil
// templates to run based on tags (comma-separated, file)
// 执行有标记的模板子集(逗号分隔,文件)
options.Tags = nil
// templates to exclude based on tags (comma-separated, file)
// 排除执行带有标记的模板(逗号分隔,文件)
options.ExcludeTags = nil
// tags to be executed even if they are excluded either by default or configuration
// 执行默认或者配置排除的标记模板
options.IncludeTags = nil
// templates to run based on template ids (comma-separated, file)
// 执行指定ID的模板逗号分隔文件
options.IncludeIds = nil
// templates to exclude based on template ids (comma-separated, file)
// 执行排除指定ID的模板逗号分隔文件
options.ExcludeIds = nil
// templates to be executed even if they are excluded either by default or configuration
// 执行默认或配置中排除的模板
options.IncludeTemplates = nil
// template or template directory to exclude (comma-separated, file)
// 要排除的模板或者模板目录(逗号分隔,文件)
options.ExcludedTemplates = nil
// template matchers to exclude in result
// 在结果中排除指定模板
options.ExcludeMatchers = nil
// templates to run based on severity
// 根据严重程度运行模板可候选的值有info,low,medium,high,critical
options.Severities = nil
// templates to exclude based on severity
// 根据严重程度排除模板可候选的值有info,low,medium,high,critical
options.ExcludeSeverities = nil
// templates to run based on protocol type
// 根据协议运行模板可候选的值有dns, file, http, headless, network, workflow, ssl, websocket, whois
options.Protocols = nil
// templates to exclude based on protocol type
// 根据协议排除模板可候选的值有dns, file, http, headless, network, workflow, ssl, websocket, whois
options.ExcludeProtocols = nil
// templates to run based on expression condition
// 根据表达式运行模板
options.IncludeConditions = nil
// output file to write found issues/vulnerabilities
// 输出发现的问题到文件 -o 参数
options.Output = ""
// store all request/response passed through nuclei to output directory
// 是否将nuclei的所有请求和响应输出到目录
options.StoreResponse = false
// store all request/response passed through nuclei to custom directory
// 将nuclei的所有请求和响应输出到指定目录默认output
options.StoreResponseDir = "output"
// display findings only
// 只显示结果
options.Silent = false
// disable output content coloring (ANSI escape codes)
// 禁用输出内容着色ANSI转义码
options.NoColor = false
// write output in JSON(Lines) format
// 输出为jsonLines
options.JSONL = false
// include request/response pairs in the JSONL output (for findings only)
// 在JSON中输出对应的请求和相应仅结果
options.JSONRequests = false
// disable printing result metadata in cli output
// 不显示匹配的元数据
options.NoMeta = false
// enables printing timestamp in cli output
options.Timestamp = false
// nuclei reporting database (always use this to persist report data)
options.ReportingDB = ""
// display match failure status
// 显示匹配失败状态
options.MatcherStatus = false
// directory to export results in markdown format
// 以markdown导出结果
options.MarkdownExportDirectory = ""
// file to export results in SARIF format
// 以SARIF导出结果
options.SarifExport = ""
// file to export results in JSON format
options.JSONExport = ""
// 指定Nuclei的配置文件
cfgFile = ""
// 为HTTP模板启用重定向
options.FollowRedirects = false
// 在同一主机上重定向
options.FollowHostRedirects = false
// HTTP模板最大重定向次数默认10
options.MaxRedirects = 10
// 为HTTP模板禁用重定向
options.DisableRedirects = false
// 指定Nuclei报告模板文件
options.ReportingConfig = ""
// 指定header、cookie以header:value的方式cli文件
options.CustomHeaders = nil
// 通过key=value指定var值
options.Vars = goflags.RuntimeMap{}
// 指定Nuclei的解析文件
options.ResolversFile = ""
// 当DNS错误时使用系统DNS
options.SystemResolvers = false
2023-09-16 17:58:50 +02:00
options.DisableClustering = false
2023-08-18 08:55:46 +02:00
// 启用被动扫描处理HTTP响应
options.OfflineHTTP = false
// 在模板中使用环境变量
options.EnvironmentVariables = false
// 用于对扫描的主机进行身份验证的客户端证书文件PEM 编码)
options.ClientCertFile = ""
// 用于对扫描的主机进行身份验证的客户端密钥文件PEM 编码)
options.ClientKeyFile = ""
// 用于对扫描的主机进行身份验证的客户端证书颁发机构文件PEM 编码)
options.ClientCAFile = ""
// 显示文件模板的匹配值,只适用于提取器
options.ShowMatchLine = false
// 对ztls自动退回到tls13
options.ZTLS = false
// 指定tls sni的主机名默认为输入的域名
options.SNI = ""
2023-09-16 17:58:50 +02:00
options.AllowLocalFileAccess = false
options.RestrictLocalNetworkAccess = false
2023-08-18 08:55:46 +02:00
// 指定网卡
options.Interface = ""
// type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
// 指定payload 组合方式
options.AttackType = ""
// 源IP
options.SourceIP = ""
// 重写默认配置路径($home/.config
options.CustomConfigDir = ""
// 最大读取响应大小默认10 * 1024 * 1024字节
options.ResponseReadSize = 10 * 1024 * 1024
// 最大储存响应大小默认1 * 1024 * 1024字节
options.ResponseSaveSize = 1 * 1024 * 1024
2023-09-16 17:58:50 +02:00
options.TlsImpersonate = false
2023-08-18 08:55:46 +02:00
// 使用interactsh反连检测平台默认为oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me
options.InteractshURL = ""
// 指定反连检测平台的身份凭证
options.InteractshToken = ""
// 指定保存在交互缓存中的请求数默认5000
options.InteractionsCacheSize = 5000
// 从缓存中删除请求前等待的时间默认为60秒
options.InteractionsEviction = 60
// 每个轮询前等待时间默认为5秒
options.InteractionsPollDuration = 5
// 退出轮询前的等待时间默认为5秒
options.InteractionsCoolDownPeriod = 5
// 禁用反连检测平台,同时排除基于反连检测的模板
options.NoInteractsh = false
// overrides fuzzing type set in template (replace, prefix, postfix, infix)
// 覆盖模板中设置的模糊类型(替换、前缀、后缀、中缀)
options.FuzzingType = ""
// overrides fuzzing mode set in template (multiple, single)
// 覆盖模板中设置的模糊模式(多个、单个)
options.FuzzingMode = ""
// 启用网络空间搜索引擎
options.Uncover = false
// 网络空间搜索引擎请求
options.UncoverQuery = nil
// 网络空间搜索引擎 fofa/shodan
options.UncoverEngine = nil
// uncover fields to return (ip,port,host)
options.UncoverField = "ip:port"
// uncover results to return
options.UncoverLimit = 100
// delay between uncover query requests in seconds (0 to disable)
2023-09-16 17:58:50 +02:00
options.UncoverRateLimit = 60
2023-08-18 08:55:46 +02:00
// 每秒最大请求量默认150
options.RateLimit = 150
// 每分钟最大请求量
options.RateLimitMinute = 0
// 每个模板最大并行检测数默认25
options.BulkSize = 64
// 并行执行的最大模板数量默认25
options.TemplateThreads = 64
// 每个模板并行运行的无头主机最大数量默认10
options.HeadlessBulkSize = 10
// 并行指定无头主机最大数量默认10
options.HeadlessTemplateThreads = 10
// 超时时间默认为10秒
2023-09-16 17:58:50 +02:00
options.Timeout = 12
// 重试次数默认1设置2为降低糟糕网络环境的影响
options.Retries = 2
2023-08-18 08:55:46 +02:00
// 指定HTTP/HTTPS默认端口例如host:80host:443
options.LeaveDefaultPorts = false
// 某主机扫描失败次数跳过该主机默认30
options.MaxHostError = 50
// 将给定错误添加到最大主机错误监视列表(标准、文件)
options.TrackError = nil
// 关闭主机基于错误的跳过
options.NoHostErrors = false
// 使用项目文件夹避免多次发送同一请求
options.Project = false // 去重复导致file missing
// 设置特定的项目文件夹
options.ProjectPath = os.TempDir()
// 得到一个结果后停止(或许会中断模板和工作流的逻辑)
options.StopAtFirstMatch = false
// 流模式 - 在不整理输入的情况下详细描述
options.Stream = false
// 扫描策略 auto/host-spray/template-spray
// options.ScanStrategy = "auto"
options.ScanStrategy = "auto"
// 输入读取超时时间默认3分钟
options.InputReadTimeout = time.Duration(3 * time.Minute)
// 禁用httpx
options.DisableHTTPProbe = true
// 禁用标准输入
options.DisableStdin = false
// 启用需要无界面浏览器的模板
options.Headless = false
// 在无界面下超时秒数默认20
options.PageTimeout = 20
// 在无界面浏览器运行模板时,显示浏览器
options.ShowBrowser = false
// 不使用Nuclei自带的浏览器使用本地浏览器
options.UseInstalledChrome = false
// 展示无界面浏览器的操作
options.ShowActions = false
// 显示所有请求和响应
options.Debug = false
// 显示所有请求
options.DebugRequests = false
// 显示所有响应
options.DebugResponse = false
// 使用http/socks5代理逗号分隔文件
if proxy == "" {
options.Proxy = nil
} else {
options.Proxy = []string{proxy}
}
// 代理所有请求
options.ProxyInternal = false
// 列出所有支持的DSL函数签名
options.ListDslSignatures = false
// 写入跟踪日志到文件
options.TraceLogFile = ""
// 写入错误日志到文件
options.ErrorLogFile = ""
// 启用Nuclei的监控
options.HangMonitor = false
// 显示详细信息
options.Verbose = false
// 将Nuclei的内存转储成文件
memProfile = ""
// 显示额外的详细信息
options.VerboseVerbose = false
// 启用pprof调试服务器
options.EnablePprof = false
// 运行诊断检查
options.HealthCheck = false
config.DefaultConfig.DisableUpdateCheck()
// 更新Nuclei模板到最新版
options.UpdateTemplates = false
// 覆盖安装模板
options.NewTemplatesDirectory = pwd + "/config/pocs/nuclei-templates/"
// 显示正在扫描的统计信息
options.EnableProgressBar = true
// 将统计信息以JSONL格式输出到文件
options.StatsJSON = false
// 显示统计信息更新的间隔秒数默认5
options.StatsInterval = 20
// 显示Nuclei端口信息
options.Metrics = false
// 更改Nuclei默认端口默认9092
options.MetricsPort = 9092
// run scan on nuclei cloud
options.Cloud = false
// add specified data source (s3,github)
options.AddDatasource = ""
// add target(s) to cloud
options.AddTarget = ""
// add template(s) to cloud
options.AddTemplate = ""
// list previous cloud scans
options.ScanList = false
// list scan output by scan id
options.ScanOutput = ""
// list cloud target by id
options.ListTargets = false
// list cloud template by id
options.ListTemplates = false
// list cloud datasource by id
options.ListDatasources = false
// list reporting sources
options.ListReportingSources = false
// delete cloud scan by id
options.DeleteScan = ""
// delete target(s) from cloud
options.RemoveTarget = ""
// delete template(s) from cloud
options.RemoveTemplate = ""
// delete specified data source
options.RemoveDatasource = ""
// disable specified reporting source
options.DisableReportingSource = ""
// enable specified reporting source
options.EnableReportingSource = ""
// get target content by id
options.GetTarget = ""
// get template content by id
options.GetTemplate = ""
// disable scan/output storage on cloud
options.NoStore = false
// do not display pretty-printed tables
options.NoTables = false
// limit the number of output to display
options.OutputLimit = 100
2023-09-13 04:36:42 +02:00
options.PocNameForSearch = nameForSearch
2023-08-18 08:55:46 +02:00
gologger.DefaultLogger.SetTimestamp(options.Timestamp, levels.LevelDebug)
cleanupOldResumeFiles()
}
// cleanupOldResumeFiles cleans up resume files older than 10 days.
func cleanupOldResumeFiles() {
root := config.DefaultConfig.GetConfigDir()
filter := fileutil.FileFilters{
OlderThan: 24 * time.Hour * 10, // cleanup on the 10th day
Prefix: "resume-",
}
_ = fileutil.DeleteFilesOlderThan(root, filter)
}
func init() {
// print stacktrace of errors in debug mode
if os.Getenv("DEBUG") != "" {
errorutil.ShowStackTrace = true
}
}