├── Customername.Perimeter.in ├── README.md └── cvescan.ps1 /Customername.Perimeter.in: -------------------------------------------------------------------------------- 1 | hostname,cpe 2 | "dc01-fw01","cpe:2.3:a:cisco:firepower_threat_defense:6.6.*" 3 | "dc01-adc01","cpe:2.3:o:citrix:application_delivery_controller_firmware:13.*" 4 | "dc01-appsrv01","cpe:2.3:a:apache:struts:2.5.*" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CVEScan 2 | List CVEs and details that apply to your infrastructure (pre-inventoried). 3 | Documentation is on the Internet Storm Center site: https://isc.sans.edu, for 7,8,11 Jan 2021: 4 | 5 | https://isc.sans.edu/forums/diary/Using+the+NIST+Database+and+API+to+Keep+Up+with+Vulnerabilities+and+Patches+Part+1+of+3/26958/ 6 | 7 | https://isc.sans.edu/forums/diary/Using+the+NIST+Database+and+API+to+Keep+Up+with+Vulnerabilities+and+Patches+Playing+with+Code+Part+2+of+3/26964/ 8 | 9 | https://isc.sans.edu/forums/diary/Using+the+NVD+Database+and+API+to+Keep+Up+with+Vulnerabilities+and+Patches+Tool+Drop+CVEScan+Part+3+of+3/26974/ 10 | 11 |
12 | Syntax:
13 | cvescan.ps1 -i CustomerName.Perimeter.in -d 90
14 |     where:
15 |        -i  CustomerName.Perimeter.in is a pre-inventoried infrastructure input file
16 |                    typically: CustomerName.Scope.in  (.in for input)
17 |                    one example Customer's perimeter is provided as an example
18 |                    
19 |        -d n        indicates how many days to pull CVE's for 
20 |                    (typically 7/30/60/90 days, depending on requirements)
21 | 
22 | I find this most useful to run for pre-inventoried customer subnets, to let them know when critical CVEs are posted that they should evaluate. This saves me from manually parsing every one of hundreds of CVEs that get posted regularly, and likely missing the 1,2,3 that are critical to my clients 23 | 24 | The output file matches the input filename (note where the dots are) 25 | 26 | I typicaly do not include MS Windows of any version or MS Office, as those should be taken care of - you need to go to a lot of effort to turn off all the update mechanisms for these, and you deserve what you get if so (sorry). 27 | 28 | However, SQL, Exchange, SCCM and so are on definitely good to include, as well as Oracle, Adobe or any other applications or infrastructure. Typically I break customer inventories into multiple "scopes": 29 | - hosts on internet perimeters (or other clear trust boundaries) 30 | - hosts on Server subnets 31 | - hosts on workstation subnets 32 | - hosts on IoT subnets (especially HealthCare and ICS / SCADA environments) 33 | -------------------------------------------------------------------------------- /cvescan.ps1: -------------------------------------------------------------------------------- 1 | ########################################################################## 2 | # CVESCANtie 3 | # Version 1.iscisc0 4 | # Assess an inventoried infrastructure from pre-inventoried CPEs and published CVEs 5 | # 6 | # Hosted at https://github.com/robvandenbrink/CVEScan 7 | # 8 | # Further documentation at: 9 | # https://isc.sans.edu/forums/diary/Using+the+NIST+Database+and+API+to+Keep+Up+with+Vulnerabilities+and+Patches+Part+1+of+3/26958/ 10 | # https://isc.sans.edu/forums/diary/Using+the+NIST+Database+and+API+to+Keep+Up+with+Vulnerabilities+and+Patches+Playing+with+Code+Part+2+of+3/26964/ 11 | # https://isc.sans.edu/forums/diary/Using+the+NVD+Database+and+API+to+Keep+Up+with+Vulnerabilities+and+Patches+Tool+Drop+CVEScan+Part+3+of+3/26974/ 12 | # 13 | # Syntax: 14 | # CVEScan.ps1 -i -d 15 | ########################################################################## 16 | 17 | param ( 18 | [alias("i")] 19 | $infile, 20 | [alias("d")] 21 | $daterange 22 | ) 23 | 24 | function helpsyntax { 25 | write-host "CVESCAN: Assess a known inventory against current CVEs" 26 | write-host "Parameters:" 27 | write-host " -i " 28 | write-host "Optional Parameters:" 29 | write-host " -d " 30 | write-host "cvescan -i perimeterdevices.in -d 60" 31 | exit 32 | } 33 | 34 | if ($daterange -eq 0) { write-host "ERROR: Must specify input filename and date range`n" ; helpsyntax } 35 | 36 | # setup 37 | $allCVEs = @() 38 | $CVEDetails = @() 39 | 40 | $apps = Import-Csv -path $infile 41 | $now = get-date 42 | $outfile = $infile.replace(".in",$now.tostring("yyyy-MM-dd_hh-mm")+"_"+$daterange+"-days.html") 43 | $StartDate = $now.adddays(-$daterange).tostring("yyyy-MM-dd")+ "T00:00:00:000%20UTC-00:00" 44 | 45 | # Collect host to CVEs table 46 | foreach ($app in $apps) { 47 | $request = "https://services.nvd.nist.gov/rest/json/cves/1.0?modStartDate=" + $StartDate + "&cpeMatchString=" + $app.cpe 48 | $CVEs = (invoke-webrequest $request | ConvertFrom-Json).result.CVE_items.cve.CVE_data_meta.id 49 | foreach ($CVE in $CVEs) { 50 | $tempobj = [pscustomobject]@{ 51 | Hostname = $app.hostname 52 | CVE = $CVE 53 | } 54 | $allCVEs += $tempobj 55 | } 56 | } 57 | 58 | $Header = @" 59 | 64 | "@ 65 | 66 | $filepath = gci $infile 67 | 68 | $Title = @() 69 | $Title += [pscustomobject]@{ Organization="Scope";bbb=$filepath.basename.split(".")[1] } 70 | $Title += [pscustomobject]@{ Organization="From Date:"; bbb=($now.adddays(-$daterange).tostring("yyyy-MM-dd")) } 71 | $Title += [pscustomobject]@{ Organization="To Date:";bbb=$now.tostring("yyyy-MM-dd") } 72 | 73 | (($Title | convertto-HTML -title "CVE Summary" -Head $header) + "


").replace("bbb",$filepath.basename.split(".")[0]) | out-file $outfile 74 | 75 | (($allCVEs | Convertto-HTML -Head $header) + "

") | out-file -append $outfile 76 | 77 | #parse out just the CVEs 78 | $justCVEs = $allCVEs | select CVE | Sort-Object | Get-Unique -AsString 79 | 80 | # collect CVE info 81 | foreach ($CVE in $justCVEs) { 82 | $h = "" 83 | $request = "https://services.nvd.nist.gov/rest/json/cve/1.0/" + $CVE.CVE 84 | $cvemetadata = (invoke-webrequest $request) | convertfrom-json 85 | $CVEURLs = $cvemetadata.result.cve_items.cve.references.reference_data.url 86 | $affectedApps = ($cvemetadata.result.CVE_items.configurations.nodes.children.cpe_match) | where {$_.vulnerable -eq "true" } | select cpe23Uri,versionendincluding 87 | 88 | # add the affected hosts back into the detailed listing 89 | # write-host $CVE.CVE 90 | foreach ($ac in $allCVEs) { 91 | if ($ac.CVE -eq $CVE.CVE) { 92 | $h += ($ac.Hostname + "
") 93 | } 94 | } 95 | 96 | $tempobj = [pscustomobject]@{ 97 | CVE = $CVE.CVE 98 | Hosts = $h 99 | # Just the datestamp, remove the clock time 100 | "Published Date" = ($cvemetadata.result.cve_items.publishedDate).split("T")[0] 101 | "CVE Description" = $cvemetadata.result.cve_items.cve.description.description_data.value 102 | Vector = $cvemetadata.result.CVE_items.impact.basemetricv3.cvssv3.attackVector 103 | "Attack Complexity" = $cvemetadata.result.CVE_items.impact.basemetricv3.cvssv3.attackComplexity 104 | "User Interaction" = $cvemetadata.result.CVE_items.impact.basemetricv3.cvssv3.userInteraction 105 | "Base Score" = $cvemetadata.result.CVE_items.impact.basemetricv3.cvssv3.baseScore 106 | "Severity" = $cvemetadata.result.CVE_items.impact.basemetricv3.cvssv3.baseSeverity 107 | "Reference URLs" = ($CVEURLs | ft -hidetableheaders | out-string).replace("`n","`n
") 108 | "Affected Apps" = ($affectedapps | ft -HideTableHeaders | out-string).replace("`n","`n
") 109 | } 110 | $CVEDetails += $tempobj 111 | } 112 | 113 | # to just view the detailed output 114 | # $CVEDetails | out-gridview 115 | 116 | # to output to HTML 117 | $Header = @" 118 | 123 | "@ 124 | 125 | # Note that the
tags get escaped, these are un-escaped below 126 | # this is a horrible hack, but I can't find a decent "elegant" way to do this 127 | # ... in less than 5x the time it took me to do it the ugly way :-) 128 | 129 | (($CVEDetails | sort -descending -property "Base Score" )| Convertto-HTML -Head $header) -replace '<br>', '
' | out-file -append $outfile 130 | --------------------------------------------------------------------------------