Initial commit.
This commit is contained in:
commit
f75d57b53a
4 changed files with 303 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
getvulns
|
37
README.md
Normal file
37
README.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# getvulns 🚨
|
||||
Utility to fetch and list current security advisories of network vendor products and os versions.
|
||||
|
||||
To be able to use this utility you need to go to
|
||||
1. Access the Cisco API console at: [https://apiconsole.cisco.com](https://apiconsole.cisco.com)
|
||||
2. Login with your CCO credentials
|
||||
3. Register your application and obtain your client credentials.
|
||||
4. Once you register your application and obtain your client ID and client secret you need to add these to your environment variables like so:
|
||||
|
||||
```bash
|
||||
$ export CLIENT_ID="0lkajsdklsajdlkj"
|
||||
$ export CLIENT_SECRET="2lk3rlncxk5l6l"
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
```bash
|
||||
$ ./getvulns -h
|
||||
Usage of ./getvulns:
|
||||
-ios string
|
||||
fetch Security Advisories for IOS version
|
||||
-iosxe string
|
||||
fetch Security Advisories for IOS-XE version
|
||||
-product string
|
||||
fetch Security Advisories Cisco Products, ex Cisco Adaptive Security Appliance
|
||||
-v be verbose
|
||||
$
|
||||
```
|
||||
|
||||
# Building
|
||||
```bash
|
||||
$ go get -u -v
|
||||
$ go build || go run main.go
|
||||
```
|
||||
|
||||
# Screenshot
|
||||
![1](assets/img/screenshot.png)
|
BIN
assets/img/screenshot.png
Normal file
BIN
assets/img/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 627 KiB |
265
main.go
Normal file
265
main.go
Normal file
|
@ -0,0 +1,265 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/fatih/color"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const oauth2Url = "https://cloudsso.cisco.com/as/token.oauth2"
|
||||
|
||||
type oauthToken struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
}
|
||||
|
||||
type ciscoVulns struct {
|
||||
Advisories []struct {
|
||||
AdvisoryID string `json:"advisoryId"`
|
||||
AdvisoryTitle string `json:"advisoryTitle"`
|
||||
BugIDs []string `json:"bugIDs"`
|
||||
IpsSignatures []string `json:"ipsSignatures"`
|
||||
Cves []string `json:"cves"`
|
||||
CvrfURL string `json:"cvrfUrl"`
|
||||
OvalURL string `json:"ovalUrl"`
|
||||
CvssBaseScore string `json:"cvssBaseScore"`
|
||||
Cwe []string `json:"cwe"`
|
||||
IosRelease []string `json:"iosRelease"`
|
||||
FirstFixed []string `json:"firstFixed"`
|
||||
FirstPublished string `json:"firstPublished"`
|
||||
LastUpdated string `json:"lastUpdated"`
|
||||
ProductNames []string `json:"productNames"`
|
||||
PublicationURL string `json:"publicationUrl"`
|
||||
Sir string `json:"sir"`
|
||||
Summary string `json:"summary"`
|
||||
} `json:"advisories"`
|
||||
SirCriticalCount int
|
||||
SirHighCount int
|
||||
SirMediumCount int
|
||||
SirLowCount int
|
||||
}
|
||||
|
||||
var verboseFlag = flag.Bool("v", false, "be verbose")
|
||||
var scriptFlag = flag.Bool("s", false, "scriptble output")
|
||||
|
||||
func main() {
|
||||
var t oauthToken
|
||||
var c ciscoVulns
|
||||
|
||||
var iosXeFlag = flag.String("iosxe", "", "fetch Security Advisories for IOS-XE version")
|
||||
var iosFlag = flag.String("ios", "", "fetch Security Advisories for IOS version")
|
||||
var productFlag = flag.String("product", "", "fetch Security Advisories Cisco Products, ex Cisco Adaptive Security Appliance")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *iosXeFlag == "" && *iosFlag == "" && *productFlag == "" {
|
||||
flag.PrintDefaults()
|
||||
return
|
||||
}
|
||||
|
||||
/* Colors */
|
||||
redstr := color.New(color.FgRed).SprintFunc()
|
||||
red := color.New(color.FgRed)
|
||||
yellow := color.New(color.FgYellow).SprintFunc()
|
||||
boldRed := red.Add(color.Bold).SprintFunc()
|
||||
|
||||
if *iosXeFlag != "" {
|
||||
err := t.fetchToken()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
c.fetchVulnVersion(t, "iosxe", *iosXeFlag)
|
||||
c.populateSirCount()
|
||||
if *scriptFlag == true {
|
||||
fmt.Printf("Summary Version: %s Critical: %d: High: %d Medium: %d Low: %d\n", *iosXeFlag, c.SirCriticalCount, c.SirHighCount, c.SirMediumCount, c.SirLowCount)
|
||||
} else {
|
||||
/* Clear terminal */
|
||||
fmt.Printf("\033[H\033[2J")
|
||||
fmt.Printf("--- Vulnerabilities for IOS-XE %s ---\n", *iosXeFlag)
|
||||
fmt.Printf("Critical: %s High: %s Medium: %s Low: %d\n\n", boldRed(c.SirCriticalCount), redstr(c.SirHighCount), yellow(c.SirMediumCount), c.SirLowCount)
|
||||
}
|
||||
}
|
||||
|
||||
if *iosFlag != "" {
|
||||
err := t.fetchToken()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
c.fetchVulnVersion(t, "ios", *iosFlag)
|
||||
c.populateSirCount()
|
||||
/* Clear terminal */
|
||||
if *scriptFlag == true {
|
||||
fmt.Printf("Summary Version: %s Critical: %d: High: %d Medium: %d Low: %d\n", *iosFlag, c.SirCriticalCount, c.SirHighCount, c.SirMediumCount, c.SirLowCount)
|
||||
} else {
|
||||
fmt.Printf("\033[H\033[2J")
|
||||
fmt.Printf("--- Vulnerabilities for IOS %s ---\n", *iosFlag)
|
||||
fmt.Printf("Critical: %s High: %s Medium: %s Low: %d\n\n", boldRed(c.SirCriticalCount), redstr(c.SirHighCount), yellow(c.SirMediumCount), c.SirLowCount)
|
||||
}
|
||||
}
|
||||
|
||||
if *productFlag != "" {
|
||||
fmt.Println("Not yet implemented.")
|
||||
}
|
||||
|
||||
if *scriptFlag == true {
|
||||
for _, vuln := range c.Advisories {
|
||||
fmt.Printf("%s:%s:%s:%s\n", vuln.AdvisoryTitle, vuln.CvssBaseScore, vuln.Sir, vuln.PublicationURL)
|
||||
}
|
||||
} else {
|
||||
for _, vuln := range c.Advisories {
|
||||
switch vuln.Sir {
|
||||
case "Critical":
|
||||
fmt.Printf("Title: %s\nCVE Score: %s\nSeverity: %s\nUrl: %s\n\n", vuln.AdvisoryTitle, vuln.CvssBaseScore, boldRed("!!! "+vuln.Sir+" !!!"), vuln.PublicationURL)
|
||||
case "High":
|
||||
fmt.Printf("Title: %s\nCVE Score: %s\nSeverity: %s\nUrl: %s\n\n", vuln.AdvisoryTitle, vuln.CvssBaseScore, redstr(vuln.Sir), vuln.PublicationURL)
|
||||
case "Medium":
|
||||
fmt.Printf("Title: %s\nCVE Score: %s\nSeverity: %s\nUrl: %s\n\n", vuln.AdvisoryTitle, vuln.CvssBaseScore, yellow(vuln.Sir), vuln.PublicationURL)
|
||||
default:
|
||||
fmt.Printf("Title: %s\nCVE Score: %s\nSeverity: %s\nUrl: %s\n\n", vuln.AdvisoryTitle, vuln.CvssBaseScore, vuln.Sir, vuln.PublicationURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ciscoVulns) populateSirCount() {
|
||||
for _, vuln := range c.Advisories {
|
||||
switch vuln.Sir {
|
||||
case "Critical":
|
||||
c.SirCriticalCount++
|
||||
case "High":
|
||||
c.SirHighCount++
|
||||
case "Medium":
|
||||
c.SirMediumCount++
|
||||
case "Low":
|
||||
c.SirLowCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ciscoVulns) fetchVulnVersion(token oauthToken, os string, version string) error {
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
timeout := time.Duration(60 * time.Second)
|
||||
client := &http.Client{
|
||||
Timeout: timeout,
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
var urlStr bytes.Buffer
|
||||
switch os {
|
||||
case "iosxe":
|
||||
urlStr.WriteString("https://api.cisco.com/security/advisories/iosxe?version=")
|
||||
case "ios":
|
||||
urlStr.WriteString("https://api.cisco.com/security/advisories/ios?version=")
|
||||
}
|
||||
|
||||
urlStr.WriteString(version)
|
||||
|
||||
url, err := url.Parse(urlStr.String())
|
||||
|
||||
request, err := http.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("Authorization", "Bearer "+token.AccessToken)
|
||||
|
||||
if *verboseFlag == true {
|
||||
fmt.Printf("Connecting to api.cisco.com\n")
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
if response.StatusCode == http.StatusUnauthorized {
|
||||
log.Println("Invalid credentials")
|
||||
return errors.New("Invalid credentials")
|
||||
}
|
||||
if *verboseFlag == true {
|
||||
fmt.Printf("Authentication ok.\nReading response\n")
|
||||
}
|
||||
data, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(data, &c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *oauthToken) fetchToken() error {
|
||||
clientId := os.Getenv("CLIENT_ID")
|
||||
clientSecret := os.Getenv("CLIENT_SECRET")
|
||||
|
||||
if clientId == "" || clientSecret == "" {
|
||||
return errors.New("You have not set correct environment variables (CLIENT_ID or CLIENT_SECRET).\n\n$ export CLIENT_ID=\"kajsdkljadslkj\"\n$ export CLIENT_SECRET=\"kljadslksjdlj\"")
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
timeout := time.Duration(60 * time.Second)
|
||||
client := &http.Client{
|
||||
Timeout: timeout,
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
form := url.Values{}
|
||||
form.Add("client_id", clientId)
|
||||
form.Add("client_secret", clientSecret)
|
||||
form.Add("grant_type", "client_credentials")
|
||||
|
||||
request, err := http.NewRequest("POST", oauth2Url, strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
if *verboseFlag == true {
|
||||
fmt.Printf("Connecting to cloudsso.cisco.com.\n")
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode == http.StatusUnauthorized {
|
||||
log.Println("Authentication failed: " + oauth2Url)
|
||||
return errors.New("Authentication failed: " + oauth2Url)
|
||||
}
|
||||
if *verboseFlag == true {
|
||||
fmt.Printf("Authenticated ok.\nAcquiring token.\n")
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in a new issue