123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- #!/usr/bin/perl
- ###############################################################################
- ##
- ## Functions for downloading and parsing Common Vulnerability DB data
- ##
- ###############################################################################
- use strict;
- use warnings;
- use LWP::UserAgent;
- use Time::ParseDate; # libtime-modules-perl
- use POSIX qw(mktime);
- use HTML::Parser;
- ## Get details of given CVE entry from NIST DB
- sub fetchCVE {
- my $cve_id = shift;
- my $cve_base_url = shift;
- my $cvss_base_url = shift;
- my $url;
- trace " Fetching $cve_id\n";
- $cve_id =~ s/^CAN/CVE/;
- ##
- ## get CVE Scores from NVD
- ##
- $url = $cvss_base_url . $cve_id;
- my $cvss = get $url;
- #die " Unable to fetch CVE $cve_id" unless defined $cve;
- unless (defined $cvss) {
- error "Failed to download CVE: $url\n";
- #return ""; # Don't die, we might still get proper date info from the CVE at MITRE..
- $cvss = "";
- }
- # Check for error pages: referenced but unpublished CVEs :-/
- if ($cvss =~ /is\ valid\ CVE\ format,\ but\ CVE\ was\ not\ found/) {
- error " $cve_id does not exist in NIST DB\n";
- #return ""; # Don't die, we might still get proper date info from the CVE at MITRE..
- }
- ##
- ## get CVE from MITRE
- ##
- $url = $cve_base_url . $cve_id;
- my $cve = get $url;
- unless (defined $cve) {
- error "Failed to download CVE: $url\n";
- return "";
- }
- # Check for error pages: referenced but unpublished CVEs :-/
- if ($cvss =~ /Could\ not\ find\ a\ CVE\ entry\ or\ candidate\ named/) {
- error " $cve_id does not exist in MITRE DB\n";
- return "";
- }
- return (join ("",$cvss, $cve));
- }
- ## Get CVE severity rating and report date and return
- ## (date base-score impact-score exploit-score)
- sub parseCVE($$) {
- my $cve_id = shift;
- my $cve = shift;
- # use worst-case info as defaults
- my $cve_date = parsedate("today");
- my $cve_base = 10;
- my $cve_impact = 10;
- my $cve_exploit = 10;
- if ($cve eq "") {
- # No details means we assume worst-case (highest score, recent bug)
- if ($cve_id =~ /LOCAL-(.*)/) {
- note " Assuming worst-case ratings for LOCAL CVE $cve_id..";
- $cve_date = parsedate("$1", NO_RELATIVE => 1, VALIDATE =>1);
- } else {
- error " Got bad data for CVE/CVSS $cve_id, using worst-case defaults..";
- }
- return ($cve_date, $cve_base, $cve_impact, $cve_exploit);
- }
-
- # Reporting Date -> $cve_date
- unless ($cve =~ /<td colspan="2">Assigned:?\s+\((\d{4})(\d{2})(\d{2})\)<\/td>/ ||
- $cve =~ /<div class="smaller">CVE Version:\s+(\d{4})(\d{2})(\d{2})<\/div>/ ||
- $cve =~ /<td colspan="3" class="note">Candidate assigned on\s+(\d{4})(\d{2})(\d{2})/) {
- error "\n\n$cve\nUnable to extract date from above CVE, assume worst-case (today)\n";
- } else {
- $cve_date = parsedate("$2/$3/$1", NO_RELATIVE => 1, VALIDATE =>1);
- }
- # Base Score -> $cve_base
- unless ($cve =~ /CVSS\sv2\sBase\sScore:<\/span><a\shref=".*>(.*)<\/a>\s\(\w+\)/) {
- error " Unable to parse CVSSv2 Base Score for $cve_id, assume worst-case\n";
- } else {
- $cve_base = $1;
- }
- # Impact Subscore -> $cve_impact
- unless ($cve =~ /<div\ class="row"><span\ class="label">Impact\ Subscore:<\/span>\s+(.*)<\/div>/) {
- error " Unable to parse CVSSv2 Impact Score for $cve_id, assume worst-case\n";
- } else {
- $cve_impact = $1;
- }
- # Exploitability Subscore -> $cve_exploit
- unless ($cve =~ /<div\ class="row"><span\ class="label">Exploitability\ Subscore:<\/span>\s+(.*)<\/div>/) {
- error " Unable to parse CVSSv2 Exploitability Score for $cve_id, assume worst-case\n";
- } else {
- $cve_exploit = $1;
- }
-
- #print "$cve_base\n";
- #print "$cve_impact\n";
- #print "$cve_exploit\n";
- return ($cve_date, $cve_base, $cve_impact, $cve_exploit);
- }
- 1;
|