Skip to content

Commit

Permalink
Map filter options with query (#45)
Browse files Browse the repository at this point in the history
* Map filter options with query

* Fix lint test

* Remove activity field and inlclude missed filed in json o/p

* Misc update

* Support lte and gte for eps percentile

* Maintain consistent order with lsi
  • Loading branch information
RamanaReddy0M authored Jan 23, 2024
1 parent 91cc586 commit 00803ba
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 64 deletions.
217 changes: 169 additions & 48 deletions runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/projectdiscovery/utils/auth/pdcp"
errorutil "github.com/projectdiscovery/utils/errors"
fileutil "github.com/projectdiscovery/utils/file"
sliceutil "github.com/projectdiscovery/utils/slice"
updateutils "github.com/projectdiscovery/utils/update"
)

Expand Down Expand Up @@ -460,11 +461,9 @@ func getCves(options Options) (*CVEBulkData, error) {
if len(options.CveIds) > 0 {
return getCvesByIds(options.CveIds)
}
if options.ListId {
return getCvesForSpecificFields([]string{"cve_id"}, options.Limit, options.Offset)
}
if options.Search != "" {
return getCvesBySearchString(options.Search, options.Limit, options.Offset)
query := constructQueryByOptions(options)
return getCvesBySearchString(query, options.Limit, options.Offset)
}
return getCvesByFilters(constructQueryParams(options))
}
Expand Down Expand Up @@ -560,27 +559,27 @@ func getCvesBySearchString(query string, limit, offset int) (*CVEBulkData, error
}

// all the root level fields are supported
func getCvesForSpecificFields(fields []string, limit, offset int) (*CVEBulkData, error) {
url := fmt.Sprintf("%s/cves?fields=%s&limit=%v&offset=%v", baseUrl, strings.Join(fields, ","), limit, offset)
// Send an HTTP GET request
response, err := makeGetRequest(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
// Check the response status code
if response.StatusCode != http.StatusOK {
return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
}
// Create a variable to store the response data
var cvesInBulk CVEBulkData
// Decode the JSON response into an array of CVEData structs
err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
if err != nil {
return nil, err
}
return &cvesInBulk, nil
}
// func getCvesForSpecificFields(fields []string, encodedParams string, limit, offset int) (*CVEBulkData, error) {
// url := fmt.Sprintf("%s/cves?fields=%s&%s&limit=%v&offset=%v", baseUrl, strings.Join(fields, ","), encodedParams, limit, offset)
// // Send an HTTP GET request
// response, err := makeGetRequest(url)
// if err != nil {
// return nil, err
// }
// defer response.Body.Close()
// // Check the response status code
// if response.StatusCode != http.StatusOK {
// return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
// }
// // Create a variable to store the response data
// var cvesInBulk CVEBulkData
// // Decode the JSON response into an array of CVEData structs
// err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
// if err != nil {
// return nil, err
// }
// return &cvesInBulk, nil
// }

var UNAUTHORIZEDERR = errorutil.New(`unexpected status code: 401 (get your free api key from https://cloud.projectdiscovery.io)`)

Expand Down Expand Up @@ -632,14 +631,15 @@ func constructQueryParams(opts Options) string {
addQueryParams(queryParams, "assignee", opts.Assignees)
}
if len(opts.CvssScore) > 0 {
cvsKey := "cvss_score"
var cvsKey string
for _, cvssScore := range opts.CvssScore {
cvsKey = "cvss_score"
if cvssScore[0] == '>' {
cvsKey = "cvss_score_gte"
cvssScore = cvssScore[1:]
cvssScore = strings.TrimSpace(cvssScore[1:])
} else if cvssScore[0] == '<' {
cvsKey = "cvss_score_lte"
cvssScore = cvssScore[1:]
cvssScore = strings.TrimSpace(cvssScore[1:])
}
queryParams.Add(cvsKey, cvssScore)
}
Expand All @@ -649,28 +649,13 @@ func constructQueryParams(opts Options) string {
ageKey := "age_in_days"
if opts.Age[0] == '>' {
ageKey = "age_in_days_gte"
opts.Age = opts.Age[1:]
opts.Age = strings.TrimSpace(opts.Age[1:])
} else if opts.Age[0] == '<' {
ageKey = "age_in_days_lte"
opts.Age = opts.Age[1:]
opts.Age = strings.TrimSpace(opts.Age[1:])
}
queryParams.Add(ageKey, opts.Age)
}
if opts.Kev == "true" {
queryParams.Add("is_exploited", "true")
} else if opts.Kev == "false" {
queryParams.Add("is_exploited", "false")
}
if opts.HasNucleiTemplate == "true" {
queryParams.Add("is_template", "true")
} else if opts.HasNucleiTemplate == "false" {
queryParams.Add("is_template", "false")
}
if opts.HasPoc == "true" {
queryParams.Add("is_poc", "true")
} else if opts.HasPoc == "false" {
queryParams.Add("is_poc", "false")
}
if len(opts.VulnStatus) > 0 {
queryParams.Add("vuln_status", strings.ToLower(opts.VulnStatus))
}
Expand All @@ -681,15 +666,26 @@ func constructQueryParams(opts Options) string {
epssKey := "epss.epss_score"
if opts.EpssScore[0] == '>' {
epssKey = "epss.epss_score_gte"
opts.EpssScore = opts.EpssScore[1:]
opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
} else if opts.EpssScore[0] == '<' {
epssKey = "epss.epss_score_lte"
opts.EpssScore = opts.EpssScore[1:]
opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
}
queryParams.Add(epssKey, opts.EpssScore)
}
if len(opts.EpssPercentile) > 0 {
addQueryParams(queryParams, "epss.epss_percentile", opts.EpssPercentile)
var epKey string
for _, ep := range opts.EpssPercentile {
epKey = "epss.epss_percentile"
if ep[0] == '>' {
epKey = "epss.epss_percentile_gte"
ep = strings.TrimSpace(ep[1:])
} else if ep[0] == '<' {
epKey = "epss.epss_percentile_lte"
ep = strings.TrimSpace(ep[1:])
}
queryParams.Add(epKey, ep)
}
}
if len(opts.CweIds) > 0 {
addQueryParams(queryParams, "cwe_id", opts.CweIds)
Expand All @@ -706,6 +702,21 @@ func constructQueryParams(opts Options) string {
if len(opts.Vendor) > 0 {
addQueryParams(queryParams, "cpe.vendor", opts.Vendor)
}
if opts.Kev == "true" {
queryParams.Add("is_exploited", "true")
} else if opts.Kev == "false" {
queryParams.Add("is_exploited", "false")
}
if opts.HasNucleiTemplate == "true" {
queryParams.Add("is_template", "true")
} else if opts.HasNucleiTemplate == "false" {
queryParams.Add("is_template", "false")
}
if opts.HasPoc == "true" {
queryParams.Add("is_poc", "true")
} else if opts.HasPoc == "false" {
queryParams.Add("is_poc", "false")
}
if opts.Hackerone == "true" {
queryParams.Add("hackerone.rank_gte", "1")
queryParams.Add("sort_asc", "hackerone.rank")
Expand All @@ -724,6 +735,116 @@ func constructQueryParams(opts Options) string {
return queryParams.Encode()
}

func constructQueryByOptions(opts Options) string {
query := opts.Search
if len(opts.Vendor) > 0 {
query = fmt.Sprintf("%s cpe.vendor:%s", query, strings.Join(opts.Vendor, ","))
}
if len(opts.Product) > 0 {
query = fmt.Sprintf("%s cpe.product:%s", query, strings.Join(opts.Product, ","))
}
if len(opts.Eproduct) > 0 {
query = fmt.Sprintf("%s cpe.product_ne:%s", query, strings.Join(opts.Eproduct, ","))
}
if len(opts.Severity) > 0 {
query = fmt.Sprintf("%s severity:%s", query, strings.Join(opts.Severity, ","))
}
if len(opts.CvssScore) > 0 {
var cvsKey string
for _, cvssScore := range opts.CvssScore {
cvsKey = "cvss_score"
if cvssScore[0] == '>' {
cvsKey = "cvss_score_gte"
cvssScore = strings.TrimSpace(cvssScore[1:])
} else if cvssScore[0] == '<' {
cvsKey = "cvss_score_lte"
cvssScore = strings.TrimSpace(cvssScore[1:])
}
query = fmt.Sprintf("%s %s:%s", query, cvsKey, cvssScore)
}
}
if len(opts.EpssScore) > 0 {
epssKey := "epss.epss_score"
if opts.EpssScore[0] == '>' {
epssKey = "epss.epss_score_gte"
opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
} else if opts.EpssScore[0] == '<' {
epssKey = "epss.epss_score_lte"
opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
}
query = fmt.Sprintf("%s %s:%s", query, epssKey, opts.EpssScore)
}
if len(opts.EpssPercentile) > 0 {
var epKey string
for _, ep := range opts.EpssPercentile {
epKey = "epss.epss_percentile"
if ep[0] == '>' {
epKey = "epss.epss_percentile_gte"
ep = strings.TrimSpace(ep[1:])
} else if ep[0] == '<' {
epKey = "epss.epss_percentile_lte"
ep = strings.TrimSpace(ep[1:])
}
query = fmt.Sprintf("%s %s:%s", query, epKey, ep)
}
}
if len(opts.Cpe) > 0 {
query = fmt.Sprintf(`%s cpe.cpe:"%s"`, query, opts.Cpe)
}
if len(opts.CweIds) > 0 {
query = fmt.Sprintf("%s cwe_id:%s", query, strings.Join(opts.CweIds, ","))
}
if len(opts.Age) > 0 {
ageKey := "age_in_days"
if opts.Age[0] == '>' {
ageKey = "age_in_days_gte"
opts.Age = strings.TrimSpace(opts.Age[1:])
} else if opts.Age[0] == '<' {
ageKey = "age_in_days_lte"
opts.Age = strings.TrimSpace(opts.Age[1:])
}
query = fmt.Sprintf("%s %s:%s", query, ageKey, opts.Age)
}
if len(opts.Assignees) > 0 {
query = fmt.Sprintf("%s assignee:%s", query, strings.Join(opts.Assignees, ","))
}
if len(opts.VulnStatus) > 0 {
query = fmt.Sprintf("%s vuln_status:%s", query, strings.ToLower(opts.VulnStatus))
}
if opts.Kev == "true" {
query = fmt.Sprintf("%s is_exploited:true", query)
} else if opts.Kev == "false" {
query = fmt.Sprintf("%s is_exploited:false", query)
}
if opts.HasNucleiTemplate == "true" {
query = fmt.Sprintf("%s is_template:true", query)
} else if opts.HasNucleiTemplate == "false" {
query = fmt.Sprintf("%s is_template:false", query)
}
if opts.HasPoc == "true" {
query = fmt.Sprintf("%s is_poc:true", query)
} else if opts.HasPoc == "false" {
query = fmt.Sprintf("%s is_poc:false", query)
}
if opts.Hackerone == "true" {
query = fmt.Sprintf("%s hackerone.rank_gte:1 sort_asc:hackerone.rank", query)
} else {
query = fmt.Sprintf("%s sort_desc:cve_id", query)
}
if opts.RemotlyExploitable == "true" {
query = fmt.Sprintf("%s is_remote:true", query)
}

parts := strings.Split(query, " ")
parts = sliceutil.PruneEmptyStrings(parts)
parts = sliceutil.Dedupe(parts)
query = strings.Join(parts, " ")
if os.Getenv("DEBUG") == "true" {
fmt.Println("constructed query: ", query)
}
return query
}

func addQueryParams(queryParams *url.Values, key string, values []string) *url.Values {
if len(values) > 0 {
for _, value := range values {
Expand Down
Loading

0 comments on commit 00803ba

Please sign in to comment.