2021-02-03 13:08:31 +05:30
|
|
|
package testutils
|
|
|
|
|
|
|
|
|
|
import (
|
2022-09-19 13:39:28 +02:00
|
|
|
"context"
|
2023-11-11 02:12:27 +03:00
|
|
|
"encoding/base64"
|
|
|
|
|
"os"
|
2022-09-19 13:39:28 +02:00
|
|
|
"time"
|
|
|
|
|
|
2022-10-12 22:04:37 -05:00
|
|
|
"github.com/projectdiscovery/ratelimit"
|
2023-10-30 19:02:06 +05:30
|
|
|
"go.uber.org/multierr"
|
2021-09-03 16:48:39 +03:00
|
|
|
|
2021-11-05 03:01:41 +05:30
|
|
|
"github.com/logrusorgru/aurora"
|
2021-11-25 17:03:56 +02:00
|
|
|
|
2021-02-27 20:54:22 +05:30
|
|
|
"github.com/projectdiscovery/gologger/levels"
|
2023-10-17 17:44:13 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/model"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
|
2021-02-03 13:08:31 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Init initializes the protocols and their configurations
|
|
|
|
|
func Init(options *types.Options) {
|
2021-02-26 13:13:11 +05:30
|
|
|
_ = protocolinit.Init(options)
|
2021-02-03 13:08:31 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultOptions is the default options structure for nuclei during mocking.
|
|
|
|
|
var DefaultOptions = &types.Options{
|
2021-11-05 15:27:49 +05:30
|
|
|
Metrics: false,
|
|
|
|
|
Debug: false,
|
|
|
|
|
DebugRequests: false,
|
|
|
|
|
DebugResponse: false,
|
|
|
|
|
Silent: false,
|
|
|
|
|
Verbose: false,
|
|
|
|
|
NoColor: true,
|
|
|
|
|
UpdateTemplates: false,
|
2023-03-31 05:59:29 -04:00
|
|
|
JSONL: false,
|
2023-07-04 16:37:56 -04:00
|
|
|
OmitRawRequests: false,
|
2021-11-05 15:27:49 +05:30
|
|
|
EnableProgressBar: false,
|
|
|
|
|
TemplateList: false,
|
|
|
|
|
Stdin: false,
|
|
|
|
|
StopAtFirstMatch: false,
|
|
|
|
|
NoMeta: false,
|
|
|
|
|
Project: false,
|
|
|
|
|
MetricsPort: 0,
|
|
|
|
|
BulkSize: 25,
|
|
|
|
|
TemplateThreads: 10,
|
|
|
|
|
Timeout: 5,
|
|
|
|
|
Retries: 1,
|
|
|
|
|
RateLimit: 150,
|
|
|
|
|
ProjectPath: "",
|
|
|
|
|
Severities: severity.Severities{},
|
|
|
|
|
Targets: []string{},
|
|
|
|
|
TargetsFilePath: "",
|
|
|
|
|
Output: "",
|
2021-11-10 10:00:03 -06:00
|
|
|
Proxy: []string{},
|
2021-11-05 15:27:49 +05:30
|
|
|
TraceLogFile: "",
|
|
|
|
|
Templates: []string{},
|
|
|
|
|
ExcludedTemplates: []string{},
|
|
|
|
|
CustomHeaders: []string{},
|
2022-11-03 20:27:18 +05:30
|
|
|
InteractshURL: "https://oast.fun",
|
2021-11-05 15:27:49 +05:30
|
|
|
InteractionsCacheSize: 5000,
|
|
|
|
|
InteractionsEviction: 60,
|
2021-11-25 18:54:16 +02:00
|
|
|
InteractionsCoolDownPeriod: 5,
|
2021-11-05 15:27:49 +05:30
|
|
|
InteractionsPollDuration: 5,
|
2023-08-01 14:33:43 -04:00
|
|
|
GitHubTemplateRepo: []string{},
|
|
|
|
|
GitHubToken: "",
|
2021-02-03 13:08:31 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TemplateInfo contains info for a mock executed template.
|
|
|
|
|
type TemplateInfo struct {
|
|
|
|
|
ID string
|
2021-07-12 17:20:01 +03:00
|
|
|
Info model.Info
|
2021-02-03 13:08:31 +05:30
|
|
|
Path string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewMockExecuterOptions creates a new mock executeroptions struct
|
2023-05-31 16:58:10 -04:00
|
|
|
func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecutorOptions {
|
2023-09-02 14:34:05 +05:30
|
|
|
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
|
2023-05-31 16:58:10 -04:00
|
|
|
executerOpts := &protocols.ExecutorOptions{
|
2021-02-03 13:08:31 +05:30
|
|
|
TemplateID: info.ID,
|
|
|
|
|
TemplateInfo: info.Info,
|
|
|
|
|
TemplatePath: info.Path,
|
2023-11-11 02:12:27 +03:00
|
|
|
Output: NewMockOutputWriter(options.OmitTemplate),
|
2021-02-03 13:08:31 +05:30
|
|
|
Options: options,
|
2021-02-26 13:13:11 +05:30
|
|
|
Progress: progressImpl,
|
2021-02-03 13:08:31 +05:30
|
|
|
ProjectFile: nil,
|
2021-02-08 02:07:19 +05:30
|
|
|
IssuesClient: nil,
|
2021-02-21 16:31:34 +05:30
|
|
|
Browser: nil,
|
2023-04-19 21:58:48 +05:30
|
|
|
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
2022-11-28 12:49:30 +05:30
|
|
|
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
2021-02-03 13:08:31 +05:30
|
|
|
}
|
2023-08-31 18:03:01 +05:30
|
|
|
executerOpts.CreateTemplateCtxStore()
|
2021-02-03 13:08:31 +05:30
|
|
|
return executerOpts
|
|
|
|
|
}
|
2021-02-27 20:54:22 +05:30
|
|
|
|
|
|
|
|
// NoopWriter is a NooP gologger writer.
|
|
|
|
|
type NoopWriter struct{}
|
|
|
|
|
|
|
|
|
|
// Write writes the data to an output writer.
|
|
|
|
|
func (n *NoopWriter) Write(data []byte, level levels.Level) {}
|
2021-11-05 03:01:41 +05:30
|
|
|
|
|
|
|
|
// MockOutputWriter is a mocked output writer.
|
|
|
|
|
type MockOutputWriter struct {
|
|
|
|
|
aurora aurora.Aurora
|
2023-11-11 02:12:27 +03:00
|
|
|
omitTemplate bool
|
2021-11-05 03:01:41 +05:30
|
|
|
RequestCallback func(templateID, url, requestType string, err error)
|
2023-09-02 14:34:05 +05:30
|
|
|
FailureCallback func(result *output.InternalEvent)
|
2021-11-05 03:01:41 +05:30
|
|
|
WriteCallback func(o *output.ResultEvent)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewMockOutputWriter creates a new mock output writer
|
2023-11-11 02:12:27 +03:00
|
|
|
func NewMockOutputWriter(omomitTemplate bool) *MockOutputWriter {
|
|
|
|
|
return &MockOutputWriter{aurora: aurora.NewAurora(false), omitTemplate: omomitTemplate}
|
2021-11-05 03:01:41 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close closes the output writer interface
|
|
|
|
|
func (m *MockOutputWriter) Close() {}
|
|
|
|
|
|
|
|
|
|
// Colorizer returns the colorizer instance for writer
|
|
|
|
|
func (m *MockOutputWriter) Colorizer() aurora.Aurora {
|
|
|
|
|
return m.aurora
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write writes the event to file and/or screen.
|
|
|
|
|
func (m *MockOutputWriter) Write(result *output.ResultEvent) error {
|
|
|
|
|
if m.WriteCallback != nil {
|
|
|
|
|
m.WriteCallback(result)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Request writes a log the requests trace log
|
|
|
|
|
func (m *MockOutputWriter) Request(templateID, url, requestType string, err error) {
|
|
|
|
|
if m.RequestCallback != nil {
|
|
|
|
|
m.RequestCallback(templateID, url, requestType, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-25 17:03:56 +02:00
|
|
|
// WriteFailure writes the event to file and/or screen.
|
2023-08-28 17:53:19 +05:30
|
|
|
func (m *MockOutputWriter) WriteFailure(wrappedEvent *output.InternalWrappedEvent) error {
|
2023-10-30 19:02:06 +05:30
|
|
|
// if failure event has more than one result, write them all
|
|
|
|
|
if len(wrappedEvent.Results) > 0 {
|
|
|
|
|
errs := []error{}
|
|
|
|
|
for _, result := range wrappedEvent.Results {
|
|
|
|
|
result.MatcherStatus = false // just in case
|
|
|
|
|
if err := m.Write(result); err != nil {
|
|
|
|
|
errs = append(errs, err)
|
|
|
|
|
}
|
2023-08-28 17:53:19 +05:30
|
|
|
}
|
2023-10-30 19:02:06 +05:30
|
|
|
if len(errs) > 0 {
|
|
|
|
|
return multierr.Combine(errs...)
|
2023-08-28 17:53:19 +05:30
|
|
|
}
|
2023-10-30 19:02:06 +05:30
|
|
|
return nil
|
2023-09-02 14:34:05 +05:30
|
|
|
}
|
2022-04-01 14:29:02 -05:00
|
|
|
|
2023-10-30 19:02:06 +05:30
|
|
|
// create event
|
|
|
|
|
event := wrappedEvent.InternalEvent
|
|
|
|
|
templatePath, templateURL := utils.TemplatePathURL(types.ToString(event["template-path"]), types.ToString(event["template-id"]))
|
|
|
|
|
var templateInfo model.Info
|
|
|
|
|
if ti, ok := event["template-info"].(model.Info); ok {
|
|
|
|
|
templateInfo = ti
|
|
|
|
|
}
|
|
|
|
|
data := &output.ResultEvent{
|
|
|
|
|
Template: templatePath,
|
|
|
|
|
TemplateURL: templateURL,
|
|
|
|
|
TemplateID: types.ToString(event["template-id"]),
|
|
|
|
|
TemplatePath: types.ToString(event["template-path"]),
|
|
|
|
|
Info: templateInfo,
|
|
|
|
|
Type: types.ToString(event["type"]),
|
|
|
|
|
Host: types.ToString(event["host"]),
|
|
|
|
|
Request: types.ToString(event["request"]),
|
|
|
|
|
Response: types.ToString(event["response"]),
|
|
|
|
|
MatcherStatus: false,
|
|
|
|
|
Timestamp: time.Now(),
|
2023-11-11 02:12:27 +03:00
|
|
|
//FIXME: this is workaround to encode the template when no results were found
|
|
|
|
|
TemplateEncoded: m.encodeTemplate(types.ToString(event["template-path"])),
|
2023-11-27 19:54:45 +01:00
|
|
|
Error: types.ToString(event["error"]),
|
2023-10-30 19:02:06 +05:30
|
|
|
}
|
|
|
|
|
return m.Write(data)
|
2022-04-01 14:29:02 -05:00
|
|
|
}
|
2021-11-22 17:53:25 +05:30
|
|
|
|
2023-11-11 02:12:27 +03:00
|
|
|
var maxTemplateFileSizeForEncoding = 1024 * 1024
|
|
|
|
|
|
|
|
|
|
func (w *MockOutputWriter) encodeTemplate(templatePath string) string {
|
|
|
|
|
data, err := os.ReadFile(templatePath)
|
|
|
|
|
if err == nil && !w.omitTemplate && len(data) <= maxTemplateFileSizeForEncoding && config.DefaultConfig.IsCustomTemplate(templatePath) {
|
|
|
|
|
return base64.StdEncoding.EncodeToString(data)
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-30 19:02:06 +05:30
|
|
|
func (m *MockOutputWriter) WriteStoreDebugData(host, templateID, eventType string, data string) {}
|
|
|
|
|
|
2021-11-05 03:01:41 +05:30
|
|
|
type MockProgressClient struct{}
|
|
|
|
|
|
|
|
|
|
// Stop stops the progress recorder.
|
|
|
|
|
func (m *MockProgressClient) Stop() {}
|
|
|
|
|
|
|
|
|
|
// Init inits the progress bar with initial details for scan
|
|
|
|
|
func (m *MockProgressClient) Init(hostCount int64, rulesCount int, requestCount int64) {}
|
|
|
|
|
|
|
|
|
|
// AddToTotal adds a value to the total request count
|
|
|
|
|
func (m *MockProgressClient) AddToTotal(delta int64) {}
|
|
|
|
|
|
|
|
|
|
// IncrementRequests increments the requests counter by 1.
|
|
|
|
|
func (m *MockProgressClient) IncrementRequests() {}
|
|
|
|
|
|
2023-01-13 13:41:05 +05:30
|
|
|
// SetRequests sets the counter by incrementing it with a delta
|
|
|
|
|
func (m *MockProgressClient) SetRequests(count uint64) {}
|
|
|
|
|
|
2021-11-05 03:01:41 +05:30
|
|
|
// IncrementMatched increments the matched counter by 1.
|
|
|
|
|
func (m *MockProgressClient) IncrementMatched() {}
|
|
|
|
|
|
|
|
|
|
// IncrementErrorsBy increments the error counter by count.
|
|
|
|
|
func (m *MockProgressClient) IncrementErrorsBy(count int64) {}
|
|
|
|
|
|
|
|
|
|
// IncrementFailedRequestsBy increments the number of requests counter by count
|
|
|
|
|
// along with errors.
|
|
|
|
|
func (m *MockProgressClient) IncrementFailedRequestsBy(count int64) {}
|