Skip to content

Commit

Permalink
pdcp result upload: bug fix + (optional) scan name support using `-sn…
Browse files Browse the repository at this point in the history
…ame` 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
  • Loading branch information
tarunKoyalwar committed May 10, 2024
1 parent 0f983d8 commit d6424ea
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 10 deletions.
13 changes: 7 additions & 6 deletions cmd/integration-test/profile-loader.go
Expand Up @@ -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
}
Expand All @@ -33,21 +33,22 @@ 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 {
results, err := testutils.RunNucleiWithArgsAndGetResults(false, "-tl", "-tp", filepath)
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
}
1 change: 1 addition & 0 deletions cmd/nuclei/main.go
Expand Up @@ -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",
Expand Down
27 changes: 24 additions & 3 deletions internal/pdcp/writer.go
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"net/http"
"net/url"
"regexp"
"sync/atomic"
"time"

Expand All @@ -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
Expand All @@ -41,6 +46,7 @@ type UploadWriter struct {
cancel context.CancelFunc
done chan struct{}
scanID string
scanName string
counter atomic.Int32
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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")
Expand Down
6 changes: 5 additions & 1 deletion internal/runner/runner.go
Expand Up @@ -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)
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/templates/compile.go
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions pkg/types/types.go
Expand Up @@ -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
Expand Down

0 comments on commit d6424ea

Please sign in to comment.