nuclei/v2/internal/runner/enumerate.go
Sandeep Singh 96646c8f53
cloud templates targets sync (#2959)
* Add s3 bucket template provider

- Refactor the custom github template code
- add interface for template provider

* Validate if aws creds are passed if bucket flag

- refactor s3 provider struct to take client
- add function which returns the aws s3 client
- update error messages

* Add aws s3 bucket flags documentation in README.md

- Rename the github_test.go to customTemplate_test.go

* go mod update

* Move template provider code to pkg/external/customtemplates dir

* Added initial data_source sync to cloud

* Misc

* Add pagination to scan output and scan list (#2858)

* Add pagination to scan output and scan list

* Use time based parameters instead of page numbers

* Fix linting errors

* Do not check limits at client, check at server

* Remove unused constant

* Misc update

* Removed unnecessary flags

* Misc

* Misc

* Misc endpoint additions

* Added more routes

* Typo fix

* Misc fixes

* Misc

* Misc fixes to cloud target logic + use int for IDs

* Misc

* Misc fixes

* Misc

* Misc fixes

* readme update

* Add JSON output support for list-scan option (#2876)

* Add JSON output support for list-scan option

* Fix typo in cloud JSON output description

* Following changes

- Update status(finished, running) to be lower-case by default
- Convert status to upper-case in DisplayScanList()

* Update status to be lower-case by default

* Remove additional json flag, instead use existing

* Merge conflict

* Accomodate comment changes and restructure code

Co-authored-by: Jaideep K <jaideep@one2n.in>

* Use integer IDs for scan tasks

* Added get-templates-targets endpoint + JSON + validation

* Added target count list

* misc option / description updates

* Added changes as per code review

* duplicate options + typo updates

* Added tablewriter for tabular data writing by default

* Fixed list scan endpoint

* Review changes

* workflow fix

* Added cloud tags etc based filtering (#3070)

* Added omitempty for filtering request

* go mod tidy

* misc format update

Co-authored-by: shubhamrasal <shubhamdharmarasal@gmail.com>
Co-authored-by: Ice3man <nizamulrana@gmail.com>
Co-authored-by: Jaideep Khandelwal <jdk2588@gmail.com>
Co-authored-by: Siddharth Shashikar <60960197+shashikarsiddharth@users.noreply.github.com>
Co-authored-by: Jaideep K <jaideep@one2n.in>
2022-12-21 22:48:43 +05:30

138 lines
4.4 KiB
Go

package runner
import (
"bytes"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"io"
_ "net/http/pprof"
"os"
"path/filepath"
"strings"
"time"
"github.com/klauspost/compress/zlib"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/internal/runner/nucleicloud"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v2/pkg/core"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"go.uber.org/atomic"
)
// runStandardEnumeration runs standard enumeration
func (r *Runner) runStandardEnumeration(executerOpts protocols.ExecuterOptions, store *loader.Store, engine *core.Engine) (*atomic.Bool, error) {
if r.options.AutomaticScan {
return r.executeSmartWorkflowInput(executerOpts, store, engine)
}
return r.executeTemplatesInput(store, engine)
}
// runCloudEnumeration runs cloud based enumeration
func (r *Runner) runCloudEnumeration(store *loader.Store, cloudTemplates, cloudTargets []string, nostore bool, limit int) (*atomic.Bool, error) {
count := &atomic.Int64{}
now := time.Now()
defer func() {
gologger.Info().Msgf("Scan execution took %s and found %d results", time.Since(now), count.Load())
}()
results := &atomic.Bool{}
// TODO: Add payload file and workflow support for private templates
catalogChecksums := nucleicloud.ReadCatalogChecksum()
targets := make([]string, 0, r.hmapInputProvider.Count())
r.hmapInputProvider.Scan(func(value *contextargs.MetaInput) bool {
targets = append(targets, value.Input)
return true
})
templates := make([]string, 0, len(store.Templates()))
privateTemplates := make(map[string]string)
for _, template := range store.Templates() {
data, _ := os.ReadFile(template.Path)
h := sha1.New()
_, _ = io.Copy(h, bytes.NewReader(data))
newhash := hex.EncodeToString(h.Sum(nil))
templateRelativePath := getTemplateRelativePath(template.Path)
if hash, ok := catalogChecksums[templateRelativePath]; ok || newhash == hash {
templates = append(templates, templateRelativePath)
} else {
privateTemplates[filepath.Base(template.Path)] = gzipBase64EncodeData(data)
}
}
taskID, err := r.cloudClient.AddScan(&nucleicloud.AddScanRequest{
RawTargets: targets,
PublicTemplates: templates,
CloudTargets: cloudTargets,
CloudTemplates: cloudTemplates,
PrivateTemplates: privateTemplates,
IsTemporary: nostore,
Filtering: getCloudFilteringFromOptions(r.options),
})
if err != nil {
return results, err
}
gologger.Info().Msgf("Created task with ID: %d", taskID)
if nostore {
gologger.Info().Msgf("Cloud scan storage: disabled")
}
time.Sleep(3 * time.Second)
err = r.cloudClient.GetResults(taskID, true, limit, func(re *output.ResultEvent) {
results.CompareAndSwap(false, true)
_ = count.Inc()
if outputErr := r.output.Write(re); outputErr != nil {
gologger.Warning().Msgf("Could not write output: %s", err)
}
if r.issuesClient != nil {
if err := r.issuesClient.CreateIssue(re); err != nil {
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
}
}
})
return results, err
}
func getTemplateRelativePath(templatePath string) string {
splitted := strings.SplitN(templatePath, "nuclei-templates", 2)
if len(splitted) < 2 {
return ""
}
return strings.TrimPrefix(splitted[1], "/")
}
func gzipBase64EncodeData(data []byte) string {
var buf bytes.Buffer
writer, _ := zlib.NewWriterLevel(&buf, zlib.BestCompression)
_, _ = writer.Write(data)
_ = writer.Close()
encoded := base64.StdEncoding.EncodeToString(buf.Bytes())
return encoded
}
func getCloudFilteringFromOptions(options *types.Options) *nucleicloud.AddScanRequestConfiguration {
return &nucleicloud.AddScanRequestConfiguration{
Authors: options.Authors,
Tags: options.Tags,
ExcludeTags: options.ExcludeTags,
IncludeTags: options.IncludeTags,
IncludeIds: options.IncludeIds,
ExcludeIds: options.ExcludeIds,
IncludeTemplates: options.IncludeTemplates,
ExcludedTemplates: options.ExcludedTemplates,
ExcludeMatchers: options.ExcludeMatchers,
Severities: options.Severities,
ExcludeSeverities: options.ExcludeSeverities,
Protocols: options.Protocols,
ExcludeProtocols: options.ExcludeProtocols,
IncludeConditions: options.IncludeConditions,
}
}