2022-11-15 01:37:00 +05:30
|
|
|
package runner
|
|
|
|
|
|
|
|
|
|
import (
|
2022-12-12 23:39:21 +05:30
|
|
|
"io"
|
2022-12-06 14:11:32 +05:30
|
|
|
"io/fs"
|
2022-12-12 23:39:21 +05:30
|
|
|
"os"
|
2022-12-06 14:11:32 +05:30
|
|
|
"path/filepath"
|
2022-12-09 00:15:18 +05:30
|
|
|
"strconv"
|
2022-11-15 01:37:00 +05:30
|
|
|
"strings"
|
|
|
|
|
|
2022-12-12 23:39:21 +05:30
|
|
|
jsoniter "github.com/json-iterator/go"
|
2022-11-15 01:37:00 +05:30
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
"github.com/projectdiscovery/gologger"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/internal/runner/nucleicloud"
|
2022-12-04 20:43:19 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
2022-11-15 01:37:00 +05:30
|
|
|
)
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
// Get all the scan lists for a user/apikey.
|
|
|
|
|
func (r *Runner) getScanList(limit int) error {
|
|
|
|
|
lastTime := "2099-01-02 15:04:05 +0000 UTC"
|
|
|
|
|
|
|
|
|
|
var e error
|
|
|
|
|
for {
|
|
|
|
|
items, err := r.cloudClient.GetScans(limit, lastTime)
|
|
|
|
|
if err != nil {
|
|
|
|
|
e = err
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if len(items) == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
for _, v := range items {
|
|
|
|
|
lastTime = v.CreatedAt.String()
|
2022-12-12 16:41:28 +05:30
|
|
|
res := nucleicloud.PrepareScanListOutput(v)
|
|
|
|
|
if r.options.JSON {
|
2022-12-12 23:39:21 +05:30
|
|
|
_ = jsoniter.NewEncoder(os.Stdout).Encode(res)
|
2022-12-12 16:41:28 +05:30
|
|
|
} else {
|
2022-12-12 23:39:21 +05:30
|
|
|
gologger.Silent().Msgf("%s [%d] [STATUS: %s] [MATCHED: %d] [TARGETS: %d] [TEMPLATES: %d] [DURATION: %s]\n", res.Timestamp, res.ScanID, strings.ToUpper(res.ScanStatus), res.ScanResult, res.Target, res.Template, res.ScanTime)
|
2022-12-04 20:43:19 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) deleteScan(id string) error {
|
2022-12-12 20:31:15 +05:30
|
|
|
ID, _ := strconv.ParseInt(id, 10, 64)
|
|
|
|
|
deleted, err := r.cloudClient.DeleteScan(ID)
|
2022-12-04 20:43:19 +05:30
|
|
|
if !deleted.OK {
|
2022-12-06 14:11:32 +05:30
|
|
|
gologger.Error().Msgf("Error in deleting the scan %s.", id)
|
2022-12-04 20:43:19 +05:30
|
|
|
} else {
|
|
|
|
|
gologger.Info().Msgf("Scan deleted %s.", id)
|
|
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) getResults(id string, limit int) error {
|
2022-12-12 20:31:15 +05:30
|
|
|
ID, _ := strconv.ParseInt(id, 10, 64)
|
|
|
|
|
err := r.cloudClient.GetResults(ID, func(re *output.ResultEvent) {
|
2022-12-04 20:43:19 +05:30
|
|
|
if outputErr := r.output.Write(re); outputErr != nil {
|
|
|
|
|
gologger.Warning().Msgf("Could not write output: %s", outputErr)
|
|
|
|
|
}
|
|
|
|
|
}, false, limit)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-12 23:39:21 +05:30
|
|
|
func (r *Runner) getTarget(id string) error {
|
|
|
|
|
ID, _ := strconv.ParseInt(id, 10, 64)
|
|
|
|
|
reader, err := r.cloudClient.GetTarget(ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not get target")
|
|
|
|
|
}
|
|
|
|
|
defer reader.Close()
|
|
|
|
|
|
|
|
|
|
_, _ = io.Copy(os.Stdout, reader)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) getTemplate(id string) error {
|
|
|
|
|
ID, _ := strconv.ParseInt(id, 10, 64)
|
|
|
|
|
reader, err := r.cloudClient.GetTemplate(ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not get template")
|
|
|
|
|
}
|
|
|
|
|
defer reader.Close()
|
|
|
|
|
|
|
|
|
|
_, _ = io.Copy(os.Stdout, reader)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
func (r *Runner) listDatasources() error {
|
|
|
|
|
datasources, err := r.cloudClient.ListDatasources()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for _, source := range datasources {
|
2022-12-12 23:39:21 +05:30
|
|
|
if r.options.JSON {
|
|
|
|
|
_ = jsoniter.NewEncoder(os.Stdout).Encode(source)
|
|
|
|
|
} else {
|
|
|
|
|
gologger.Silent().Msgf("[%s] [%d] [%s] [%s] %s", source.Updatedat.Format(nucleicloud.DDMMYYYYhhmmss), source.ID, source.Type, source.Repo, source.Path)
|
|
|
|
|
}
|
2022-12-04 21:48:05 +05:30
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) listTargets() error {
|
2022-12-06 14:11:32 +05:30
|
|
|
items, err := r.cloudClient.ListTargets("")
|
2022-12-04 21:48:05 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for _, source := range items {
|
2022-12-12 23:39:21 +05:30
|
|
|
if r.options.JSON {
|
|
|
|
|
_ = jsoniter.NewEncoder(os.Stdout).Encode(source)
|
|
|
|
|
} else {
|
2022-12-13 13:39:10 +05:30
|
|
|
gologger.Silent().Msgf("[%d] %s (%d)", source.ID, source.Reference, source.Count)
|
2022-12-12 23:39:21 +05:30
|
|
|
}
|
2022-12-04 21:48:05 +05:30
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) listTemplates() error {
|
2022-12-06 14:11:32 +05:30
|
|
|
items, err := r.cloudClient.ListTemplates("")
|
2022-12-04 21:48:05 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for _, source := range items {
|
2022-12-12 23:39:21 +05:30
|
|
|
if r.options.JSON {
|
|
|
|
|
_ = jsoniter.NewEncoder(os.Stdout).Encode(source)
|
|
|
|
|
} else {
|
|
|
|
|
gologger.Silent().Msgf("[%d] %s", source.ID, source.Reference)
|
|
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 23:02:18 +05:30
|
|
|
func (r *Runner) removeDatasource(datasource string) error {
|
2022-12-09 13:11:43 +05:30
|
|
|
var source string
|
|
|
|
|
ID, parseErr := strconv.ParseInt(datasource, 10, 64)
|
|
|
|
|
if parseErr != nil {
|
|
|
|
|
source = datasource
|
|
|
|
|
}
|
2022-12-09 00:15:18 +05:30
|
|
|
|
2022-12-09 13:11:43 +05:30
|
|
|
err := r.cloudClient.RemoveDatasource(ID, source)
|
|
|
|
|
if err == nil {
|
2022-12-06 14:11:32 +05:30
|
|
|
gologger.Info().Msgf("Datasource deleted %s", datasource)
|
|
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) addTemplate(location string) error {
|
|
|
|
|
walkErr := filepath.WalkDir(location, func(path string, d fs.DirEntry, err error) error {
|
2022-12-09 14:55:51 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-12-06 14:11:32 +05:30
|
|
|
if d.IsDir() || !strings.HasSuffix(path, ".yaml") {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
base := filepath.Base(path)
|
|
|
|
|
reference, templateErr := r.cloudClient.AddTemplate(base, path)
|
|
|
|
|
if templateErr != nil {
|
|
|
|
|
gologger.Error().Msgf("Could not upload %s: %s", path, templateErr)
|
2022-12-10 22:21:32 +05:30
|
|
|
} else if reference != "" {
|
2022-12-06 14:11:32 +05:30
|
|
|
gologger.Info().Msgf("Uploaded template %s: %s", base, reference)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
return walkErr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) addTarget(location string) error {
|
|
|
|
|
walkErr := filepath.WalkDir(location, func(path string, d fs.DirEntry, err error) error {
|
2022-12-09 14:55:51 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-12-06 14:11:32 +05:30
|
|
|
if d.IsDir() || !strings.HasSuffix(path, ".txt") {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
base := filepath.Base(location)
|
|
|
|
|
reference, targetErr := r.cloudClient.AddTarget(base, location)
|
|
|
|
|
if targetErr != nil {
|
|
|
|
|
gologger.Error().Msgf("Could not upload %s: %s", location, targetErr)
|
2022-12-10 22:21:32 +05:30
|
|
|
} else if reference != "" {
|
|
|
|
|
gologger.Info().Msgf("Uploaded target %s: %s", base, reference)
|
2022-12-06 14:11:32 +05:30
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
return walkErr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) removeTarget(item string) error {
|
|
|
|
|
response, err := r.cloudClient.ListTargets(item)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not list targets")
|
|
|
|
|
}
|
|
|
|
|
for _, item := range response {
|
|
|
|
|
if err := r.cloudClient.RemoveTarget(item.ID); err != nil {
|
|
|
|
|
gologger.Error().Msgf("Error in deleting target %s: %s", item.Reference, err)
|
|
|
|
|
} else {
|
|
|
|
|
gologger.Info().Msgf("Target deleted %s", item.Reference)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) removeTemplate(item string) error {
|
|
|
|
|
response, err := r.cloudClient.ListTemplates(item)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not list templates")
|
|
|
|
|
}
|
|
|
|
|
for _, item := range response {
|
|
|
|
|
if err := r.cloudClient.RemoveTemplate(item.ID); err != nil {
|
|
|
|
|
gologger.Error().Msgf("Error in deleting template %s: %s", item.Reference, err)
|
|
|
|
|
} else {
|
|
|
|
|
gologger.Info().Msgf("Template deleted %s", item.Reference)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return err
|
2022-12-05 23:02:18 +05:30
|
|
|
}
|
|
|
|
|
|
2022-11-15 01:37:00 +05:30
|
|
|
// initializeCloudDataSources initializes cloud data sources
|
2022-12-09 00:15:18 +05:30
|
|
|
func (r *Runner) initializeCloudDataSources() error {
|
2022-11-24 14:00:17 +05:30
|
|
|
if r.options.AwsBucketName != "" {
|
|
|
|
|
token := strings.Join([]string{r.options.AwsAccessKey, r.options.AwsSecretKey, r.options.AwsRegion}, ":")
|
2022-12-09 00:15:18 +05:30
|
|
|
if _, err := r.processDataSourceItem(r.options.AwsBucketName, token, "s3"); err != nil {
|
|
|
|
|
return err
|
2022-11-24 14:00:17 +05:30
|
|
|
}
|
|
|
|
|
}
|
2022-11-15 01:37:00 +05:30
|
|
|
for _, repo := range r.options.GithubTemplateRepo {
|
2022-12-09 00:15:18 +05:30
|
|
|
if _, err := r.processDataSourceItem(repo, r.options.GithubToken, "github"); err != nil {
|
|
|
|
|
return err
|
2022-11-24 14:00:17 +05:30
|
|
|
}
|
|
|
|
|
}
|
2022-12-09 00:15:18 +05:30
|
|
|
return nil
|
2022-11-24 14:00:17 +05:30
|
|
|
}
|
2022-11-15 01:37:00 +05:30
|
|
|
|
2022-12-09 00:15:18 +05:30
|
|
|
func (r *Runner) processDataSourceItem(repo, token, Type string) (int64, error) {
|
2022-11-24 14:00:17 +05:30
|
|
|
ID, err := r.cloudClient.StatusDataSource(nucleicloud.StatusDataSourceRequest{Repo: repo, Token: token})
|
|
|
|
|
if err != nil {
|
2022-12-07 00:23:32 +05:30
|
|
|
if !strings.Contains(err.Error(), "no rows in result set") {
|
2022-12-09 00:15:18 +05:30
|
|
|
return 0, errors.Wrap(err, "could not get data source status")
|
2022-11-24 14:00:17 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gologger.Info().Msgf("Adding new data source + syncing: %s\n", repo)
|
2022-12-09 00:15:18 +05:30
|
|
|
resp, err := r.cloudClient.AddDataSource(nucleicloud.AddDataSourceRequest{Type: Type, Repo: repo, Token: token})
|
2022-11-24 14:00:17 +05:30
|
|
|
if err != nil {
|
2022-12-09 00:15:18 +05:30
|
|
|
return 0, errors.Wrap(err, "could not add data source")
|
2022-11-24 14:00:17 +05:30
|
|
|
}
|
2022-12-09 00:15:18 +05:30
|
|
|
ID = resp.ID
|
|
|
|
|
if err = r.cloudClient.SyncDataSource(resp.ID); err != nil {
|
|
|
|
|
return 0, errors.Wrap(err, "could not sync data source")
|
2022-11-24 14:00:17 +05:30
|
|
|
}
|
2022-12-09 13:11:43 +05:30
|
|
|
if resp.Secret != "" {
|
2022-12-09 00:15:18 +05:30
|
|
|
gologger.Info().Msgf("Webhook URL for added source: %s/datasources/%s/webhook", r.options.CloudURL, resp.Hash)
|
2022-12-09 13:11:43 +05:30
|
|
|
gologger.Info().Msgf("Secret for webhook: %s", resp.Secret)
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-11-24 14:00:17 +05:30
|
|
|
}
|
|
|
|
|
if r.options.UpdateTemplates {
|
2022-12-09 13:11:43 +05:30
|
|
|
gologger.Info().Msgf("Syncing data source: %s (%d)\n", repo, ID)
|
2022-11-24 14:00:17 +05:30
|
|
|
if err = r.cloudClient.SyncDataSource(ID); err != nil {
|
2022-12-09 00:15:18 +05:30
|
|
|
return 0, errors.Wrap(err, "could not sync data source")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
|
|
|
|
}
|
2022-11-24 14:00:17 +05:30
|
|
|
return ID, nil
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|