Skip to content

Commit

Permalink
Exploits family enricher (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
fishkerez committed Feb 13, 2023
1 parent 63a3cdf commit d43aa9c
Show file tree
Hide file tree
Showing 24 changed files with 1,360 additions and 77 deletions.
10 changes: 10 additions & 0 deletions .families.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,13 @@ secrets:
scanners_config:
gitleaks:
binary_path: "/usr/local/bin/gitleaks"

exploits:
enabled: true
scanners_list:
- "exploitdb"
inputs: []
input_from_vuln: true
scanners_config:
exploit_db:
base_url: "http://localhost:1326"
8 changes: 6 additions & 2 deletions api/models/models.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1135,9 +1135,17 @@ components:
ExploitInfo:
type: object
properties:
name:
type: string
title:
type: string
description:
type: string
vulnerabilities:
cveID:
type: string
sourceDB:
type: string
urls:
type: array
items:
type: string
Expand Down
116 changes: 58 additions & 58 deletions api/server/server.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 76 additions & 0 deletions cli/cmd/exportresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/openclarity/vmclarity/api/client"
"github.com/openclarity/vmclarity/api/models"
"github.com/openclarity/vmclarity/shared/pkg/families"
"github.com/openclarity/vmclarity/shared/pkg/families/exploits"
"github.com/openclarity/vmclarity/shared/pkg/families/results"
"github.com/openclarity/vmclarity/shared/pkg/families/sbom"
"github.com/openclarity/vmclarity/shared/pkg/families/secrets"
Expand Down Expand Up @@ -371,6 +372,72 @@ func convertSecretsResultToAPIModel(secretsResults *secrets.Results) *models.Sec
}
}

func convertExploitsResultToAPIModel(exploitsResults *exploits.Results) *models.ExploitScan {
if exploitsResults == nil || exploitsResults.Exploits == nil {
return &models.ExploitScan{}
}

// nolint:prealloc
var retExploits []models.Exploit

for i := range exploitsResults.Exploits {
exploit := exploitsResults.Exploits[i]
retExploits = append(retExploits, models.Exploit{
ExploitInfo: &models.ExploitInfo{
CveID: &exploit.CveID,
Description: &exploit.Description,
Name: &exploit.Name,
SourceDB: &exploit.SourceDB,
Title: &exploit.Title,
Urls: &exploit.URLs,
},
Id: &exploit.ID,
})
}

if retExploits == nil {
return &models.ExploitScan{}
}

return &models.ExploitScan{
Exploits: &retExploits,
}
}

func (e *Exporter) ExportExploitsResult(res *results.Results) error {
scanResults, err := e.getExistingScanResult()
if err != nil {
return err
}

if scanResults.Status == nil {
scanResults.Status = &models.TargetScanStatus{}
}
if scanResults.Status.Exploits == nil {
scanResults.Status.Exploits = &models.TargetScanState{}
}

var errors []string

exploitsResults, err := results.GetResult[*exploits.Results](res)
if err != nil {
errors = append(errors, fmt.Errorf("failed to get exploits results from scan: %w", err).Error())
} else {
scanResults.Exploits = convertExploitsResultToAPIModel(exploitsResults)
}

state := models.DONE
scanResults.Status.Exploits.State = &state
scanResults.Status.Exploits.Errors = &errors

err = e.patchExistingScanResult(scanResults)
if err != nil {
return err
}

return nil
}

func (e *Exporter) ExportResults(res *results.Results, famerr families.RunErrors) []error {
var errors []error
if config.SBOM.Enabled {
Expand Down Expand Up @@ -400,5 +467,14 @@ func (e *Exporter) ExportResults(res *results.Results, famerr families.RunErrors
}
}

if config.Exploits.Enabled {
err := e.ExportExploitsResult(res)
if err != nil {
err = fmt.Errorf("failed to export exploits results to server: %w", err)
logger.Error(err)
errors = append(errors, err)
}
}

return errors
}
120 changes: 120 additions & 0 deletions cli/cmd/exportresults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"github.com/openclarity/kubeclarity/shared/pkg/scanner"

"github.com/openclarity/vmclarity/api/models"
"github.com/openclarity/vmclarity/shared/pkg/families/exploits"
common2 "github.com/openclarity/vmclarity/shared/pkg/families/exploits/common"
"github.com/openclarity/vmclarity/shared/pkg/families/sbom"
"github.com/openclarity/vmclarity/shared/pkg/families/secrets"
"github.com/openclarity/vmclarity/shared/pkg/families/secrets/common"
Expand Down Expand Up @@ -316,3 +318,121 @@ func Test_convertSecretsResultToAPIModel(t *testing.T) {
})
}
}

func Test_convertExploitsResultToAPIModel(t *testing.T) {
exploit1 := common2.Exploit{
ID: "id1",
Name: "name1",
Title: "title1",
Description: "desc 1",
CveID: "cve1",
URLs: []string{"url1"},
SourceDB: "db1",
}
exploit2 := common2.Exploit{
ID: "id2",
Name: "name2",
Title: "title2",
Description: "desc 2",
CveID: "cve2",
URLs: []string{"url2"},
SourceDB: "db2",
}
exploit3 := common2.Exploit{
ID: "id3",
Name: "name3",
Title: "title3",
Description: "desc 3",
CveID: "cve3",
URLs: []string{"url3"},
SourceDB: "db3",
}
type args struct {
exploitsResults *exploits.Results
}
tests := []struct {
name string
args args
want *models.ExploitScan
}{
{
name: "nil exploitsResults",
args: args{
exploitsResults: nil,
},
want: &models.ExploitScan{},
},
{
name: "nil exploitsResults.Exploits",
args: args{
exploitsResults: &exploits.Results{
Exploits: nil,
},
},
want: &models.ExploitScan{},
},
{
name: "sanity",
args: args{
exploitsResults: &exploits.Results{
Exploits: exploits.MergedExploits{
{
Exploit: exploit1,
},
{
Exploit: exploit2,
},
{
Exploit: exploit3,
},
},
},
},
want: &models.ExploitScan{
Exploits: &[]models.Exploit{
{
ExploitInfo: &models.ExploitInfo{
CveID: utils.StringPtr(exploit1.CveID),
Description: utils.StringPtr(exploit1.Description),
Name: utils.StringPtr(exploit1.Name),
SourceDB: utils.StringPtr(exploit1.SourceDB),
Title: utils.StringPtr(exploit1.Title),
Urls: &exploit1.URLs,
},
Id: utils.StringPtr(exploit1.ID),
},
{
ExploitInfo: &models.ExploitInfo{
CveID: utils.StringPtr(exploit2.CveID),
Description: utils.StringPtr(exploit2.Description),
Name: utils.StringPtr(exploit2.Name),
SourceDB: utils.StringPtr(exploit2.SourceDB),
Title: utils.StringPtr(exploit2.Title),
Urls: &exploit2.URLs,
},
Id: utils.StringPtr(exploit2.ID),
},
{
ExploitInfo: &models.ExploitInfo{
CveID: utils.StringPtr(exploit3.CveID),
Description: utils.StringPtr(exploit3.Description),
Name: utils.StringPtr(exploit3.Name),
SourceDB: utils.StringPtr(exploit3.SourceDB),
Title: utils.StringPtr(exploit3.Title),
Urls: &exploit3.URLs,
},
Id: utils.StringPtr(exploit3.ID),
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := convertExploitsResultToAPIModel(tt.args.exploitsResults)
if diff := cmp.Diff(tt.want, got, cmpopts.SortSlices(func(a, b models.Exploit) bool { return *a.Id < *b.Id })); diff != "" {
t.Errorf("convertExploitsResultToAPIModel() mismatch (-want +got):\n%s", diff)
}
})
}
}
Loading

0 comments on commit d43aa9c

Please sign in to comment.