Add filter software by CVE and make osquery-perf also push vulnerable software (#3902)

* Add filter software by CVE and make osquery-perf also push vulnerable software

* Update based on review comments
This commit is contained in:
Tomas Touceda 2022-01-28 10:05:11 -03:00 committed by GitHub
parent 99468ff477
commit e956b0ba04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 190 additions and 16 deletions

View File

@ -0,0 +1 @@
* Add filter software by CVE

View File

@ -26,6 +26,32 @@ import (
//go:embed *.tmpl
var templatesFS embed.FS
//go:embed *.software
var softwareFS embed.FS
var vulnerableSoftware []fleet.Software
func init() {
vulnerableSoftwareData, err := softwareFS.ReadFile("vulnerable.software")
if err != nil {
log.Fatal("reading vulnerable software file: ", err)
}
lines := bytes.Split(vulnerableSoftwareData, []byte("\n"))
for _, line := range lines {
parts := bytes.Split(line, []byte("##"))
if len(parts) < 2 {
fmt.Println("skipping", string(line))
continue
}
vulnerableSoftware = append(vulnerableSoftware, fleet.Software{
Name: string(parts[0]),
Version: string(parts[1]),
Source: "apps",
})
}
log.Printf("Loaded %d vulnerable software\n", len(vulnerableSoftware))
}
type Stats struct {
errors int
enrollments int
@ -120,7 +146,7 @@ func (n *nodeKeyManager) Add(nodekey string) {
type agent struct {
agentIndex int
softwareCount entityCount
softwareCount softwareEntityCount
userCount entityCount
policyPassProb float64
strings map[string]string
@ -146,10 +172,15 @@ type entityCount struct {
unique int
}
type softwareEntityCount struct {
entityCount
vulnerable int
}
func newAgent(
agentIndex int,
serverAddress, enrollSecret string, templates *template.Template,
configInterval, queryInterval time.Duration, softwareCount, userCount entityCount,
configInterval, queryInterval time.Duration, softwareCount softwareEntityCount, userCount entityCount,
policyPassProb float64,
) *agent {
transport := http.DefaultTransport.(*http.Transport).Clone()
@ -386,7 +417,12 @@ func (a *agent) SoftwareMacOS() []fleet.Software {
Source: "osquery-perf",
}
}
randomVulnerableSoftware := make([]fleet.Software, a.softwareCount.vulnerable)
for i := 0; i < len(randomVulnerableSoftware); i++ {
randomVulnerableSoftware[i] = vulnerableSoftware[rand.Intn(len(vulnerableSoftware))]
}
software := append(commonSoftware, uniqueSoftware...)
software = append(software, randomVulnerableSoftware...)
rand.Shuffle(len(software), func(i, j int) {
software[i], software[j] = software[j], software[i]
})
@ -575,6 +611,7 @@ func main() {
nodeKeyFile := flag.String("node_key_file", "", "File with node keys to use")
commonSoftwareCount := flag.Int("common_software_count", 10, "Number of common of installed applications reported to fleet")
uniqueSoftwareCount := flag.Int("unique_software_count", 10, "Number of unique installed applications reported to fleet")
vulnerableSoftwareCount := flag.Int("vulnerable_software_count", 10, "Number of vulnerable installed applications reported to fleet")
commonUserCount := flag.Int("common_user_count", 10, "Number of common host users reported to fleet")
uniqueUserCount := flag.Int("unique_user_count", 10, "Number of unique host users reported to fleet")
policyPassProb := flag.Float64("policy_pass_prob", 1.0, "Probability of policies to pass [0, 1]")
@ -602,9 +639,12 @@ func main() {
}
for i := 0; i < *hostCount; i++ {
a := newAgent(i+1, *serverURL, *enrollSecret, tmpl, *configInterval, *queryInterval, entityCount{
a := newAgent(i+1, *serverURL, *enrollSecret, tmpl, *configInterval, *queryInterval, softwareEntityCount{
entityCount: entityCount{
common: *commonSoftwareCount,
unique: *uniqueSoftwareCount,
},
vulnerable: *vulnerableSoftwareCount,
}, entityCount{
common: *commonUserCount,
unique: *uniqueUserCount,

View File

@ -0,0 +1,108 @@
monal##4.9
flash_player##10.3.183.90
office##2021
meetings##5.8.0
kinza##5.0.1
insync##6.8.0
last.fm_desktop##2.1.39
ipvanish##3.0.11
galaxy##1.2.54
autocad##2022
globalprotect##5.1.2
malwarebytes##4.0
wing_ftp_server##6.2.3
wd_discovery##4.0.251.0
intercept_x##9.10.1
safe##17.7
edgerover##1.5.0-576
fusion##8.5
true_image##2021
internet_security##21.1
knox##2.2.0
remote_desktop##10.6.7
1password##7.2.3
canvas_draw##5.0.0
arq##5.9
parallels_desktop##16.5.0
windscribe##2.02.9
zoom##4.6.9
connect##3.2.7
armorlock##1.4.1
home##10.0.3
photoline##20.53
vpn_universal_secure_enterprise_client##2.02
nordvpn##3.3.10
wire##3.9.2943
proxifier##3.5
pulse_secure_desktop_client##9.0r1
liquidvpn##1.37
forticlient##7.0.1
endpoint_security##10.7.5
royal_tsx##3.3
realone_player##9.0.0.297
anyconnect_secure_mobility_client##4.9.03047
macos##9
office_long_term_servicing_channel##2021
remotepc##7.6.9
norton_security##13.0.1
macos_server##5.11
zoom_plugin_for_microsoft_outlook##5.7.6.76
rumpus##8.2.14
kanaka##2.8
dashlane##6.5.0
anti-virus_for_sophos_home##2.2.6
origin##10.5.86
outlook##2016
proxyman##1.9.3
forklift##3.4
vpn_universal_secure_entry_client##2.02
realplayer##12.0.1.1738
foxmail##1.2
purevpn##6.0.1
hipchat##4.30
jabber##12.9\(3\)
quicken_2018##5.2.2
shimo##4.1.5.1
evernote##8.3.2
vtune_profiler##2020
hide.me##3.3.0
visual_studio_2019##8.9
mcafee_agent##5.6.6
antivirus##9.0
maxthon_browser##5.1.46
renderman##22.3.0
install_norton_security##7.6
line##4.3.1
nextcloud##2.7.0
zenmate##1.5.4
anti-virus_for_sophos_central##9.9.6
ibackup##3.3.1.5
join.me##3.9.0.11823
ni-pal##20.0.1
privatevpn##2.0.31
cyber_security##6.8.300.0
malion##5.2.1
endpoint_protection##14
ubridge##0.9.9
vyprvpn##3.0
skype##8.59.0.77
sourcetree##3.1
hugo##0.9
excel##2019
password_manager##5.0.1073
cactusvpn##6.5.0
spectrum_protect_client##8.1.6
horizon##5.2.0
airmail_3##3.5.9
viscosity##1.4.1
switchvpn##2.1012.03
pcoip_soft_client##20.10.1
keybase##2.12.6
backblaze##7.0.1.434
hisuite##9.1.0.312
anydesk##6.1.0
swoole##1.6.7
stashcat##3.9.2
endpoint_antivirus##6.8.1.0
webex_meetings##40.1.8.5
autocad_lt##2022

View File

@ -5947,7 +5947,7 @@ Transforms a host name into a host id. For example, the Fleet UI use this endpoi
| per_page | integer | query | Results per page. |
| order_key | string | query | What to order results by. Can be ordered by the following fields: `name`, `hosts_count`. Defaults to the hosts count, descending. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default if not provided is `asc`. |
| query | string | query | Search query keywords. Searchable fields include `name`. |
| query | string | query | Search query keywords. Searchable fields include `name`, `version`, and `cve`. |
| team_id | integer | query | _Available in Fleet Premium_ Filters the software to only include the software installed on the hosts that are assigned to the specified team. |
| vulnerable | bool | query | If true or 1, only list software that has detected vulnerabilities |

View File

@ -267,16 +267,6 @@ func selectSoftwareSQL(hostID *uint, opts fleet.SoftwareListOptions) (string, []
).Where(goqu.I("h.team_id").Eq(opts.TeamID))
}
if match := opts.MatchQuery; match != "" {
match = likePattern(match)
ds = ds.Where(
goqu.Or(
goqu.I("s.name").ILike(match),
goqu.I("s.version").ILike(match),
),
)
}
ds = ds.GroupBy(
goqu.I("s.id"),
goqu.I("s.name"),
@ -304,6 +294,23 @@ func selectSoftwareSQL(hostID *uint, opts fleet.SoftwareListOptions) (string, []
goqu.I("s.id").Eq(goqu.I("scp.software_id")),
),
)
if opts.MatchQuery != "" {
ds = ds.LeftJoin(
goqu.I("software_cve").As("scv"),
goqu.On(goqu.I("scp.id").Eq(goqu.I("scv.cpe_id"))),
)
}
}
if match := opts.MatchQuery; match != "" {
match = likePattern(match)
ds = ds.Where(
goqu.Or(
goqu.I("s.name").ILike(match),
goqu.I("s.version").ILike(match),
goqu.I("scv.cve").ILike(match),
),
)
}
if opts.WithHostCounts {

View File

@ -452,6 +452,24 @@ func testSoftwareList(t *testing.T, ds *Datastore) {
test.ElementsMatchSkipID(t, software, expected)
})
t.Run("filters specific cves", func(t *testing.T) {
software := listSoftwareCheckCount(t, ds, 1, 1, fleet.SoftwareListOptions{ListOptions: fleet.ListOptions{MatchQuery: "cve-321-432-543"}}, true)
expected := []fleet.Software{foo001}
test.ElementsMatchSkipID(t, software, expected)
software = listSoftwareCheckCount(t, ds, 1, 1, fleet.SoftwareListOptions{ListOptions: fleet.ListOptions{MatchQuery: "cve-333-444-555"}}, true)
expected = []fleet.Software{foo001}
test.ElementsMatchSkipID(t, software, expected)
// partial cve
software = listSoftwareCheckCount(t, ds, 1, 1, fleet.SoftwareListOptions{ListOptions: fleet.ListOptions{MatchQuery: "333-444"}}, true)
expected = []fleet.Software{foo001}
test.ElementsMatchSkipID(t, software, expected)
// unknown CVE
listSoftwareCheckCount(t, ds, 0, 0, fleet.SoftwareListOptions{ListOptions: fleet.ListOptions{MatchQuery: "cve-000-000-000"}}, true)
})
t.Run("filters by query", func(t *testing.T) {
// query by name (case insensitive)
software := listSoftwareCheckCount(t, ds, 1, 1, fleet.SoftwareListOptions{ListOptions: fleet.ListOptions{MatchQuery: "baR"}}, true)