Skip to content
This repository has been archived by the owner on Dec 1, 2024. It is now read-only.

Commit

Permalink
vulndb diff (#152)
Browse files Browse the repository at this point in the history
* [cvefeed] Fix vulenrability typo

* [vulndb] Add a command to diff two vulnerability feeds
  • Loading branch information
dlespiau authored Jun 22, 2020
1 parent 2dc8079 commit aed862a
Show file tree
Hide file tree
Showing 4 changed files with 420 additions and 1 deletion.
121 changes: 121 additions & 0 deletions cmd/vulndb/diffcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) Facebook, Inc. and its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"path/filepath"
"sort"

"github.com/facebookincubator/nvdtools/cvefeed"
"github.com/spf13/cobra"
)

func init() {
RootCmd.AddCommand(diffCmd)
}

func feedLoad(file string) (cvefeed.Dictionary, error) {
log.Printf("loading %s\n", file)
dict, err := cvefeed.LoadJSONDictionary(file)
if err != nil {
return nil, fmt.Errorf("failed to load dictionary %s: %v", file, err)
}
return dict, nil
}

func feedName(file string) string {
return filepath.Base(file[:len(file)-5])
}

func printArraySorted(a []string, indent string, n int) {
min := func(a, b int) int {
if a <= b {
return a
}
return b
}

sort.Strings(a)
for i := 0; i < min(len(a), n); i++ {
fmt.Printf("%s%s\n", indent, a[i])
}
if len(a) > n {
fmt.Printf("%s... (%d more)\n", indent, len(a)-10)
}
}

var diffCmd = &cobra.Command{
Use: "diff [flags] a.json b.json",
Short: "diff two vulnerability feeds",
RunE: func(cmd *cobra.Command, args []string) error {
percentInt := func(a, b int) float64 {
return float64(a) / float64(b) * 100
}

if len(args) != 2 {
return errors.New("missing JSON export files")
}

aDict, err := feedLoad(args[0])
if err != nil {
return err
}

bDict, err := feedLoad(args[1])

if err != nil {
return err
}

log.Println("computing stats")

a := feedName(args[0])
b := feedName(args[1])

stats := cvefeed.Diff(a, aDict, b, bDict)

fmt.Printf("Num vulnerabilities in %s: %d\n", a, stats.NumVulnsA())
fmt.Printf("Num vulnerabilities in %s: %d\n", b, stats.NumVulnsB())
fmt.Printf("Num vulnerabilities in %s but not in %s: %d\n", a, b, stats.NumVulnsANotB())
printArraySorted(stats.VulnsANotB(), " ", 10)
fmt.Printf("Num vulnerabilities in %s but not in %s: %d\n", b, a, stats.NumVulnsBNotA())
printArraySorted(stats.VulnsBNotA(), " ", 10)
fmt.Println()
fmt.Printf("Different vulnerabilities: %d\n", stats.NumDiffVulns())
fmt.Printf(" different descriptions: %d (%.2f%%, total %.2f%%)\n",
stats.NumChunk(cvefeed.ChunkDescription), stats.PercentChunk(cvefeed.ChunkDescription),
percentInt(stats.NumChunk(cvefeed.ChunkDescription), stats.NumVulnsA()))
fmt.Printf(" different scores : %d (%.2f%%, total %.2f%%)\n",
stats.NumChunk(cvefeed.ChunkScore), stats.PercentChunk(cvefeed.ChunkScore),
percentInt(stats.NumChunk(cvefeed.ChunkScore), stats.NumVulnsA()))

log.Println("writing differences to stats.json")

data, err := json.MarshalIndent(stats, "", " ")
if err != nil {
return fmt.Errorf("failed to encode stats to JSON: %w", err)
}
if err := ioutil.WriteFile("stats.json", data, 0644); err != nil {
return fmt.Errorf("failed to write stats file: %w", err)
}

return nil
},
}
2 changes: 1 addition & 1 deletion cvefeed/dictionary.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (d *Dictionary) Override(d2 Dictionary) {
}
}

// LoadJSONDictionary parses dictionary from multiple NVD vulenrability feed JSON files
// LoadJSONDictionary parses dictionary from multiple NVD vulnerability feed JSON files
func LoadJSONDictionary(paths ...string) (Dictionary, error) {
return LoadFeed(loadJSONFile, paths...)
}
Expand Down
Loading

0 comments on commit aed862a

Please sign in to comment.