forked from future-architect/vuls
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support scanning Ubuntu using Gost (future-architect#1243)
* chore: add vuls binary in gitignore * feat(gost): support ubuntu * chore(debian): fix typo * feat(ubuntu): more detail on CveContent * chore: update .gitignore * chore: update gost deps * feat(ubuntu): add test in gost/ubuntu * chore: fix typo * Revert "chore: fix typo" This reverts commit 9f2f1db. * docs: update README
- Loading branch information
Showing
9 changed files
with
350 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
// +build !scanner | ||
|
||
package gost | ||
|
||
import ( | ||
"encoding/json" | ||
"strings" | ||
|
||
"github.com/future-architect/vuls/logging" | ||
"github.com/future-architect/vuls/models" | ||
"github.com/future-architect/vuls/util" | ||
gostmodels "github.com/knqyf263/gost/models" | ||
) | ||
|
||
// Ubuntu is Gost client for Ubuntu | ||
type Ubuntu struct { | ||
Base | ||
} | ||
|
||
func (ubu Ubuntu) supported(version string) bool { | ||
_, ok := map[string]string{ | ||
"1404": "trusty", | ||
"1604": "xenial", | ||
"1804": "bionic", | ||
"2004": "focal", | ||
"2010": "groovy", | ||
"2104": "hirsute", | ||
}[version] | ||
return ok | ||
} | ||
|
||
// DetectCVEs fills cve information that has in Gost | ||
func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) { | ||
ubuReleaseVer := strings.Replace(r.Release, ".", "", 1) | ||
if !ubu.supported(ubuReleaseVer) { | ||
logging.Log.Warnf("Ubuntu %s is not supported yet", r.Release) | ||
return 0, nil | ||
} | ||
|
||
linuxImage := "linux-image-" + r.RunningKernel.Release | ||
// Add linux and set the version of running kernel to search Gost. | ||
if r.Container.ContainerID == "" { | ||
newVer := "" | ||
if p, ok := r.Packages[linuxImage]; ok { | ||
newVer = p.NewVersion | ||
} | ||
r.Packages["linux"] = models.Package{ | ||
Name: "linux", | ||
Version: r.RunningKernel.Version, | ||
NewVersion: newVer, | ||
} | ||
} | ||
|
||
packCvesList := []packCves{} | ||
if ubu.DBDriver.Cnf.IsFetchViaHTTP() { | ||
url, _ := util.URLPathJoin(ubu.DBDriver.Cnf.GetURL(), "ubuntu", ubuReleaseVer, "pkg") | ||
responses, err := getAllUnfixedCvesViaHTTP(r, url) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
for _, res := range responses { | ||
ubuCves := map[string]gostmodels.UbuntuCVE{} | ||
if err := json.Unmarshal([]byte(res.json), &ubuCves); err != nil { | ||
return 0, err | ||
} | ||
cves := []models.CveContent{} | ||
for _, ubucve := range ubuCves { | ||
cves = append(cves, *ubu.ConvertToModel(&ubucve)) | ||
} | ||
packCvesList = append(packCvesList, packCves{ | ||
packName: res.request.packName, | ||
isSrcPack: res.request.isSrcPack, | ||
cves: cves, | ||
}) | ||
} | ||
} else { | ||
if ubu.DBDriver.DB == nil { | ||
return 0, nil | ||
} | ||
for _, pack := range r.Packages { | ||
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name) | ||
cves := []models.CveContent{} | ||
for _, ubucve := range ubuCves { | ||
cves = append(cves, *ubu.ConvertToModel(&ubucve)) | ||
} | ||
packCvesList = append(packCvesList, packCves{ | ||
packName: pack.Name, | ||
isSrcPack: false, | ||
cves: cves, | ||
}) | ||
} | ||
|
||
// SrcPack | ||
for _, pack := range r.SrcPackages { | ||
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name) | ||
cves := []models.CveContent{} | ||
for _, ubucve := range ubuCves { | ||
cves = append(cves, *ubu.ConvertToModel(&ubucve)) | ||
} | ||
packCvesList = append(packCvesList, packCves{ | ||
packName: pack.Name, | ||
isSrcPack: true, | ||
cves: cves, | ||
}) | ||
} | ||
} | ||
|
||
delete(r.Packages, "linux") | ||
|
||
for _, p := range packCvesList { | ||
for _, cve := range p.cves { | ||
v, ok := r.ScannedCves[cve.CveID] | ||
if ok { | ||
if v.CveContents == nil { | ||
v.CveContents = models.NewCveContents(cve) | ||
} else { | ||
v.CveContents[models.UbuntuAPI] = cve | ||
} | ||
} else { | ||
v = models.VulnInfo{ | ||
CveID: cve.CveID, | ||
CveContents: models.NewCveContents(cve), | ||
Confidences: models.Confidences{models.UbuntuAPIMatch}, | ||
} | ||
nCVEs++ | ||
} | ||
|
||
names := []string{} | ||
if p.isSrcPack { | ||
if srcPack, ok := r.SrcPackages[p.packName]; ok { | ||
for _, binName := range srcPack.BinaryNames { | ||
if _, ok := r.Packages[binName]; ok { | ||
names = append(names, binName) | ||
} | ||
} | ||
} | ||
} else { | ||
if p.packName == "linux" { | ||
names = append(names, linuxImage) | ||
} else { | ||
names = append(names, p.packName) | ||
} | ||
} | ||
|
||
for _, name := range names { | ||
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{ | ||
Name: name, | ||
FixState: "open", | ||
NotFixedYet: true, | ||
}) | ||
} | ||
r.ScannedCves[cve.CveID] = v | ||
} | ||
} | ||
return nCVEs, nil | ||
} | ||
|
||
// ConvertToModel converts gost model to vuls model | ||
func (ubu Ubuntu) ConvertToModel(cve *gostmodels.UbuntuCVE) *models.CveContent { | ||
references := []models.Reference{} | ||
for _, r := range cve.References { | ||
if strings.Contains(r.Reference, "https://cve.mitre.org/cgi-bin/cvename.cgi?name=") { | ||
references = append(references, models.Reference{Source: "CVE", Link: r.Reference}) | ||
} else { | ||
references = append(references, models.Reference{Link: r.Reference}) | ||
} | ||
} | ||
|
||
for _, b := range cve.Bugs { | ||
references = append(references, models.Reference{Source: "Bug", Link: b.Bug}) | ||
} | ||
|
||
for _, u := range cve.Upstreams { | ||
for _, upstreamLink := range u.UpstreamLinks { | ||
references = append(references, models.Reference{Source: "UPSTREAM", Link: upstreamLink.Link}) | ||
} | ||
} | ||
|
||
return &models.CveContent{ | ||
Type: models.UbuntuAPI, | ||
CveID: cve.Candidate, | ||
Summary: cve.Description, | ||
Cvss2Severity: cve.Priority, | ||
Cvss3Severity: cve.Priority, | ||
SourceLink: "https://ubuntu.com/security/" + cve.Candidate, | ||
References: references, | ||
Published: cve.PublicDate, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package gost | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
"time" | ||
|
||
"github.com/future-architect/vuls/models" | ||
gostmodels "github.com/knqyf263/gost/models" | ||
) | ||
|
||
func TestUbuntu_Supported(t *testing.T) { | ||
type args struct { | ||
ubuReleaseVer string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want bool | ||
}{ | ||
{ | ||
name: "14.04 is supported", | ||
args: args{ | ||
ubuReleaseVer: "1404", | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "16.04 is supported", | ||
args: args{ | ||
ubuReleaseVer: "1604", | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "18.04 is supported", | ||
args: args{ | ||
ubuReleaseVer: "1804", | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "20.04 is supported", | ||
args: args{ | ||
ubuReleaseVer: "2004", | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "20.10 is supported", | ||
args: args{ | ||
ubuReleaseVer: "2010", | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "21.04 is supported", | ||
args: args{ | ||
ubuReleaseVer: "2104", | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "empty string is not supported yet", | ||
args: args{ | ||
ubuReleaseVer: "", | ||
}, | ||
want: false, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
ubu := Ubuntu{} | ||
if got := ubu.supported(tt.args.ubuReleaseVer); got != tt.want { | ||
t.Errorf("Ubuntu.Supported() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestUbuntuConvertToModel(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
input gostmodels.UbuntuCVE | ||
expected models.CveContent | ||
}{ | ||
{ | ||
name: "gost Ubuntu.ConvertToModel", | ||
input: gostmodels.UbuntuCVE{ | ||
Candidate: "CVE-2021-3517", | ||
PublicDate: time.Date(2021, 5, 19, 14, 15, 0, 0, time.UTC), | ||
References: []gostmodels.UbuntuReference{ | ||
{Reference: "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3517"}, | ||
{Reference: "https://gitlab.gnome.org/GNOME/libxml2/-/issues/235"}, | ||
{Reference: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/bf22713507fe1fc3a2c4b525cf0a88c2dc87a3a2"}}, | ||
Description: "description.", | ||
Notes: []gostmodels.UbuntuNote{}, | ||
Bugs: []gostmodels.UbuntuBug{{Bug: "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=987738"}}, | ||
Priority: "medium", | ||
Patches: []gostmodels.UbuntuPatch{ | ||
{PackageName: "libxml2", ReleasePatches: []gostmodels.UbuntuReleasePatch{ | ||
{ReleaseName: "focal", Status: "needed", Note: ""}, | ||
}}, | ||
}, | ||
Upstreams: []gostmodels.UbuntuUpstream{{ | ||
PackageName: "libxml2", UpstreamLinks: []gostmodels.UbuntuUpstreamLink{ | ||
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/50f06b3efb638efb0abd95dc62dca05ae67882c2"}, | ||
}, | ||
}}, | ||
}, | ||
expected: models.CveContent{ | ||
Type: models.UbuntuAPI, | ||
CveID: "CVE-2021-3517", | ||
Summary: "description.", | ||
Cvss2Severity: "medium", | ||
Cvss3Severity: "medium", | ||
SourceLink: "https://ubuntu.com/security/CVE-2021-3517", | ||
References: []models.Reference{ | ||
{Source: "CVE", Link: "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3517"}, | ||
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/issues/235"}, | ||
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/bf22713507fe1fc3a2c4b525cf0a88c2dc87a3a2"}, | ||
{Source: "Bug", Link: "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=987738"}, | ||
{Source: "UPSTREAM", Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/50f06b3efb638efb0abd95dc62dca05ae67882c2"}}, | ||
Published: time.Date(2021, 5, 19, 14, 15, 0, 0, time.UTC), | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
ubu := Ubuntu{} | ||
got := ubu.ConvertToModel(&tt.input) | ||
if !reflect.DeepEqual(got, &tt.expected) { | ||
t.Errorf("Ubuntu.ConvertToModel() = %#v, want %#v", got, &tt.expected) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.