1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
#!/usr/bin/perl
#
# Compare the Debian list of CVEs with the NVD list of CVEs using CPE
# ids, to see if the set of affected packages match.
use warnings;
use strict;
use XML::Simple;
use Data::Dumper;
use vars qw($debug %cpemap %cperevmap %cvemap %reportedmissing);
$| = 1;
open(my $fh, "<", "data/CPE/list") || die;
while (<$fh>) {
chomp;
my ($binpkg, $cpe) = split(/;/);
if ($cpe) {
$cpemap{$binpkg} = $cpe;
$cperevmap{$cpe} = $binpkg;
}
}
close $fh;
open ($fh, "<", "data/CVE/list") || die;
my $cve;
while (<$fh>) {
chomp;
$cve = $1 if (m/^(CVE-\S+)\s*/);
s/^(\s+)\[\S+\] /$1/; # Trim away distribution name
if (m/^\s+- (\S+)\S*/ && ! m/<not-affected>/) {
my $srcpkg = $1;
if (exists $cvemap{$cve}) {
push(@{$cvemap{$cve}}, $srcpkg);
} else {
$cvemap{$cve} = [$srcpkg];
}
}
}
close $fh;
#
# Fetched from http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-2008.xml
#
for my $cvelist
(
"nvdcve-2.0-2011.xml",
# "nvdcve-2.0-2010.xml",
# "nvdcve-2.0-2009.xml",
# "nvdcve-2.0-2008.xml",
) {
print "Loading $cvelist\n" if $debug;
my $ref = XMLin("../../" . $cvelist);
for my $cve (sort keys %{$ref->{entry}}) {
print "Checking $cve\n" if $debug;
my $entry = $ref->{entry}->{$cve};
my %info;
my @debiancpe = get_debian_cpe($cve);
for my $cpe (@debiancpe) {
$info{$cpe} = 1;
}
my @products;
if (exists $entry->{'vuln:vulnerable-software-list'}->{'vuln:product'}) {
if ("ARRAY" eq ref $entry->{'vuln:vulnerable-software-list'}->{'vuln:product'}) {
@products = @{$entry->{'vuln:vulnerable-software-list'}->{'vuln:product'}};
} else {
@products = ($entry->{'vuln:vulnerable-software-list'}->{'vuln:product'});
}
}
for my $cpe (@products) {
if (exists $info{cpe_product($cpe)}) {
$info{cpe_product($cpe)} += 2;
} else {
$info{cpe_product($cpe)} = 2;
}
}
for my $cpe (sort keys %info) {
if (1 == $info{$cpe}) {
my %shortlist;
map { $shortlist{cpe_product($_)} = 1 } @products;
my $cpelist = join(", ", keys %shortlist);
print STDERR "warning: $cve in Debian refer to $cpe, while NVD do not (found $cpelist).\n"
} elsif (2 == $info{$cpe}) {
if (exists $cperevmap{$cpe}) {
my $binpkg = $cperevmap{$cpe};
print STDERR "warning: $cve in NVD is not refering to $cpe found in Debian.\n"
}
} elsif (3 == $info{$cpe}) {
}
}
}
print "Done loading $cvelist\n" if $debug;
}
for my $missing (sort { $reportedmissing{$a} <=> $reportedmissing{$b} }
keys %reportedmissing) {
my $count = $reportedmissing{$missing};
print STDERR "error: $cve: missing CPE ID for $missing ($count)\n";
}
sub get_debian_cpe {
my ($cve) = shift;
my %cpe;
for my $binpkg (@{$cvemap{$cve}}) {
if (exists $cpemap{$binpkg}) {
$cpe{$cpemap{$binpkg}} = 1;
} else {
$reportedmissing{$binpkg} = exists $reportedmissing{$binpkg} ?
$reportedmissing{$binpkg} + 1 : 1;
}
}
return sort keys %cpe;
}
sub cpe_product {
my $cpe = shift;
return join(":", (split(/:/, $cpe))[0..3]);
}
|