pdcp result upload: bug fix + (optional) scan name support using -sname flag (#5155)

* add default template severity and error when validating

* ignore workflows when validating severity

* add scan name support in pdcp result upload

* scan upload: fix missing name query param

* make profile-loader integration tests generic

* add scan-id validation

* ignore invalid scan id's
This commit is contained in:
Tarun Koyalwar 2024-05-11 00:44:14 +05:30 committed by GitHub
parent 0f983d8204
commit d6424ea5d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 52 additions and 10 deletions

View File

@ -20,8 +20,8 @@ func (h *profileLoaderByRelFile) Execute(testName string) error {
if err != nil {
return errorutil.NewWithErr(err).Msgf("failed to load template with id")
}
if len(results) < 100 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 100, len(results))
if len(results) <= 10 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 10, len(results))
}
return nil
}
@ -33,12 +33,13 @@ func (h *profileLoaderById) Execute(testName string) error {
if err != nil {
return errorutil.NewWithErr(err).Msgf("failed to load template with id")
}
if len(results) < 100 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 100, len(results))
if len(results) <= 10 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 10, len(results))
}
return nil
}
// this profile with load kevs
type customProfileLoader struct{}
func (h *customProfileLoader) Execute(filepath string) error {
@ -46,8 +47,8 @@ func (h *customProfileLoader) Execute(filepath string) error {
if err != nil {
return errorutil.NewWithErr(err).Msgf("failed to load template with id")
}
if len(results) < 267 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 267, len(results))
if len(results) < 1 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 1, len(results))
}
return nil
}

View File

@ -414,6 +414,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.DynamicVar(&pdcpauth, "auth", "true", "configure projectdiscovery cloud (pdcp) api key"),
flagSet.BoolVarP(&options.EnableCloudUpload, "cloud-upload", "cup", false, "upload scan results to pdcp dashboard"),
flagSet.StringVarP(&options.ScanID, "scan-id", "sid", "", "upload scan results to given scan id"),
flagSet.StringVarP(&options.ScanName, "scan-name", "sname", "", "scan name to set (optional)"),
)
flagSet.CreateGroup("Authentication", "Authentication",

View File

@ -9,6 +9,7 @@ import (
"io"
"net/http"
"net/url"
"regexp"
"sync/atomic"
"time"
@ -27,9 +28,13 @@ const (
appendEndpoint = "/v1/scans/%s/import"
flushTimer = time.Duration(1) * time.Minute
MaxChunkSize = 1024 * 1024 * 4 // 4 MB
xidRe = `^[a-z0-9]{20}$`
)
var _ output.Writer = &UploadWriter{}
var (
xidRegex = regexp.MustCompile(xidRe)
_ output.Writer = &UploadWriter{}
)
// UploadWriter is a writer that uploads its output to pdcp
// server to enable web dashboard and more
@ -41,6 +46,7 @@ type UploadWriter struct {
cancel context.CancelFunc
done chan struct{}
scanID string
scanName string
counter atomic.Int32
}
@ -86,8 +92,17 @@ func NewUploadWriter(ctx context.Context, creds *pdcpauth.PDCPCredentials) (*Upl
}
// SetScanID sets the scan id for the upload writer
func (u *UploadWriter) SetScanID(id string) {
func (u *UploadWriter) SetScanID(id string) error {
if !xidRegex.MatchString(id) {
return fmt.Errorf("invalid scan id provided")
}
u.scanID = id
return nil
}
// SetScanName sets the scan name for the upload writer
func (u *UploadWriter) SetScanName(name string) {
u.scanName = name
}
func (u *UploadWriter) autoCommit(ctx context.Context, r *io.PipeReader) {
@ -220,7 +235,13 @@ func (u *UploadWriter) getRequest(bin []byte) (*retryablehttp.Request, error) {
return nil, errorutil.NewWithErr(err).Msgf("could not create cloud upload request")
}
// add pdtm meta params
req.URL.RawQuery = updateutils.GetpdtmParams(config.Version)
req.URL.Params.Merge(updateutils.GetpdtmParams(config.Version))
// if it is upload endpoint also include name if it exists
if u.scanName != "" && req.URL.Path == uploadEndpoint {
req.URL.Params.Add("name", u.scanName)
}
req.URL.Update()
req.Header.Set(pdcpauth.ApiKeyHeaderName, u.creds.APIKey)
req.Header.Set("Content-Type", "application/octet-stream")
req.Header.Set("Accept", "application/json")

View File

@ -414,7 +414,11 @@ func (r *Runner) setupPDCPUpload(writer output.Writer) output.Writer {
return writer
}
if r.options.ScanID != "" {
uploadWriter.SetScanID(r.options.ScanID)
// ignore and use empty scan id if invalid
_ = uploadWriter.SetScanID(r.options.ScanID)
}
if r.options.ScanName != "" {
uploadWriter.SetScanName(r.options.ScanName)
}
return output.NewMultiWriter(writer, uploadWriter)
}

View File

@ -16,6 +16,7 @@ import (
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/js/compiler"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
@ -341,6 +342,18 @@ func parseTemplate(data []byte, options protocols.ExecutorOptions) (*Template, e
return nil, errors.New("no template author field provided")
}
// use default unknown severity
if len(template.Workflows) == 0 {
if template.Info.SeverityHolder.Severity == severity.Undefined {
// set unknown severity with counter and forced warning
template.Info.SeverityHolder.Severity = severity.Unknown
if options.Options.Validate {
// when validating return error
return nil, errors.New("no template severity field provided")
}
}
}
// Setting up variables regarding template metadata
options.TemplateID = template.ID
options.TemplateInfo = template.Info

View File

@ -377,6 +377,8 @@ type Options struct {
EnableCloudUpload bool
// ScanID is the scan ID to use for cloud upload
ScanID string
// ScanName is the name of the scan to be uploaded
ScanName string
// JsConcurrency is the number of concurrent js routines to run
JsConcurrency int
// SecretsFile is file containing secrets for nuclei