Initial commit.

This commit is contained in:
Kalle Carlbark 2019-09-09 15:14:49 +02:00
commit f75d57b53a
No known key found for this signature in database
GPG key ID: 3FC0C93C5A5A0670
4 changed files with 303 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
getvulns

37
README.md Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 KiB

265
main.go Normal file
View 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
}