Welcome to the CVE checker user guide. The purpose of this document is to guide you through the installation and usage of CVE checker. But before we start with that, a little warning is in place...
CVE checker does not provide security for your system. It is nothing more than a tool that attempts to identify installed software on your system and match those against the online database of CVE entries. As the identification of installed software depends on simple rules that are added by the community, it is very likely that it only detects a small portion of the installed software on your system (especially if you are running software that isn't all that popular). And even if the tool detects the software appropriately, it still requires that the CVE entry mentions this software with the same vendor and product name as this tool detects - if not, CVE checker will not be able to match the installed software against the online CVE database.
Okay, now that that is out of the way, let's start with the CVE checker installation.
The cvechecker tool requires the following packages to be installed:
libxslt - needed for the XSLT transformations (the online CVE database exists of XML files and we need to convert those to CSV so that we can easily import it into our own, local database)
libconfig - a C library that offers a simple way for applications to read and handle configuration files
a database or database client. Currently, cvechecker supports:
sqlite3 - a local, embedded yet powerful database
mysql (through libmysql) - one of the more popular open source databases
wget - a command-line tool to fetch online resources
If your distribution already offers cvechecker through its package management system, I strongly advise that you use that. The installation instructions in this section assume that you do the installation manually (and should reflect the steps that the distribution package management system does for you).
First, download the latest cvechecker package from https://github.com/sjvermeu/cvechecker/wiki/Download (or https://github.com/sjvermeu/cvechecker/releases), then extract it into a temporary directory:
~$ tar xvzf cvechecker-1.O.tar.gz
You need to select the database you want to use. cvechecker currently supports mysql and sqlite, and this support is enabled through the ./configure --enable-sqlite3
or ./configure --enable-mysql
options. You can select both too (they are not mutually exclusive) but you need to select at least one of them.
Inside the extracted folder, first run ./configure
with the proper --enable-<database>
options, followed by make
and make install
. If you use the default settings, it will install the files inside /usr/local
, so you might need root privileges to perform the make install
step.
~$ cd cvechecker-1.0
~$ ./configure --enable-sqlite3
...
~$ make
...
~$ sudo -i
~# make install
If the ./configure
step fails (especially when using the live code rather than a specific release), first run the following command:
~$ autoreconf --force --install
Finally, create a group called cvechecker and change the permissions of the installed folders so that this group has write privileges inside the directory. These steps are performed when executing make postinstall
(you almost definitely need root privileges now):
~# make postinstall
With the software now installed, you need to perform an initial configuration. This includes the setup of the databases, creation of the user you are going to use to run cvechecker and initial pull of the CVE entries from the Internet.
First, create a user that you will use to run cvechecker. The tool does not require root privileges, so I recommend not to use root. I personally use a dedicated user whose sole purpose is to, on a daily basis, pull the latest updates from the Internet, generate a report and mail that report to me. Make sure that this user is inside the cvechecker group:
~# gpasswd -a youruser cvechecker
Log on as that user, make sure his primary group is cvechecker and set the umask to 002 or higher (such as 007).
~# su youruser -
~$ newgrp cvechecker
~$ umask 007
Now, initialize the databases by running cvechecker
-i
. This will create the sqlite3 databases or, if MySQL is selected, create the appropriate tables and indexes in the selected MySQL database (the tool does not create a MySQL database itself).
~$ cvechecker -i
The cvechecker command uses a configuration file which it looks for in the location pointed to by the CVECHECKER_CONFFILE
variable or, if that variable is not set, the users' home directory (${HOME}/.cvechecker.rc
), /usr/local/etc/cvechecker.conf
or /etc/cvechecker.conf
, in that order. The first configuration file that parses correctly is used, the rest is ignored (so there is no accumulation of configurations). Below, you'll find an example configuration file which shows both the sqlite3 and mysql support:
#
# Generic settings
#
dbtype = "mysql";
#dbtype = "sqlite3";
cvecache = "/var/lib/cvechecker/cache";
datadir = "/usr/share/cvechecker";
stringcmd = "/usr/bin/strings -n 3 '@file@'";
version_url = "https://raw.github.com/sjvermeu/cvechecker/master/versions.dat";
#userkey = "servertag";
#
# For SQLite3
#
sqlite3: {
localdb = "/var/lib/cvechecker/local";
globaldb = "/var/lib/cvechecker/global.db";
};
#
# For MySQL
#
mysql: {
dbname = "cvechecker";
dbuser = "cvechecker_rw";
dbpass = "passwordforcvechecker_rw";
dbhost = "mysql.company.com";
};
Most of the parameters (like cvecache, datadir, version_url and even localdb and globaldb) will most likely be set correctly already during the installation. However, it doesn't hurt to validate if the locations mentioned are correct and that the user that will be used to run cvechecker has the rights to write (to) files in the locations.
If you opt to use the sqlite3 databases, you need to initialize those by running cvechecker -i
. Because cvechecker uses a lot of data, it will create various database files to spread the data due to performance reasons. These locations are mentioned in the configuration file.
~# cvechecker -i
This is all that is needed to initialize the SQLite3 databases.
If you opt to use the MySQL database, you first need to create the database in your MySQL server. Installing and configuring a MySQL server is beyond the scope of this document. Once a database is created (say "cvechecker"), you can either initialize it through cvechecker -i
(if the user you connect to the database to has sufficient privileges to drop and create tables and indexes) or use the dump file mysql_cvechecker.sql
available in /usr/share/cvechecker/.
~# cvechecker -i
It is strongly advised that the user you use has limited rights. Only the initialization requires additional rights. When you are using cvechecker, it is recommended that two roles are used:
A cvechecker administrative role that has the rights to load new CVE and CPE data as well as version matching rules
A cvechecker operational role that has the rights to insert the matching data and read the CVE and version matching rules
We will talk about these roles later in this document.
Our last step is to load the upstream data in the databases.
The upstream data consists out of
CVE information (CVE identifiers together with the software they are referring to) which is going to be pulled from nvd.nist.gov, and
version matching rules (regular expressions and other information needed to deduce the correct software and version given an application file or binary) which is going to be pulled from the cvechecker source code repository
These steps are automated in a tool called pullcves
. This will take a very long time, so please be patient (loading over half a million CVE entries in a database is a time consuming - but one-time - activity). Future pulls will not take this much time as they will not redownload the CVE entries from all previous years (unless you ask it to).
~$ pullcves pull
cvechecker tries to detect if its back-end was created with an earlier version of cvechecker and update the back-end accordingly. For sqlite3 databases, this usually isn't a problem as the tool has the rights to add tables and indexes when needed.
However, when using MySQL databases, it is very likely that the user you use is not authorized to update the back-end. To fix this, first run cvechecker on the administrative host (where a more privileged MySQL account can be used). It will update the back-ends for all users as well. When new(er) versions are made available, we will also add the necessary upgrade SQL scripts to launch so that you do not have to run cvechecker with a database owner account.
Whenever you want to perform a regular cvechecker run, you should schedule five steps. If you use sqlite as the database backend, all steps are to be scheduled on the same system. If you use MySQL however, it is recommended to schedule the administrative tasks on a single system (the "master" that is responsible for keeping the upstream data up-to-date) and the operational tasks on all systems where you want to run cvechecker on (and gather reports from).
The administrative tasks are:
pull in the latest CVE entries as well as software/version detection rules
The operational tasks are:
generate a list of files to scan
gather installed software/version information
output which CVE entries might affect your system
generate a report informing you about the CVE entries
All these steps should be performed by the user you use to run cvechecker, so don't forget:
~$ newgrp cvechecker
~$ umask 007
To pull the necessary data from the Internet, run pullcves pull
:
~$ pullcves pull
cvechecker uses a text file which sums up the files to scan. I recommend that you provide it with a list of all executables files plus /proc/version (on Linux). The latter allows cvechecker to verify if there are kernel-related CVE entries for your Linux kernel.
~$ find / -type f -perm -o+x > scanlist.txt
~$ echo "/proc/version" >> scanlist.txt
It is strongly advised to either umount or exclude file systems on which no useful files are located (or that belong to different operating systems, like a mounted Windows partition). You can use the -mount
(or -xdev
) option of find
to stay within the selected device (partition), or exclude directories (and their subdirectories), like so:
~$ find / -path /mnt -prune -o -path /media -prune -o -type f -perm -o+x > scanlist.txt
Import the generated scanlist.txt file in cvechecker. During the import, cvechecker will output the software/versions it detected:
~$ cvechecker -b scanlist.txt
You can integrate cvechecker with your package manager, telling cvechecker to only add (or remove) files part of an installed (or uninstalled) package rather than having to feed a full file system listing. To do so, tell your package manager to call cvechecker -d -b <file>
after each succesfull installation, or cvechecker -D -b <file>
before a desinstallation. The -d option tells cvechecker to add the file content to the database (rather than replace) whereas -D tells cvechecker to delete those entries in the database that are also in the file.
A simple example for Gentoo would be to create a script (/etc/portage/bashrc) which calls other scripts based on the ebuild phase, such as /etc/portage/bashrc.d/package.postinst
or /etc/portage/bashrc.d/package.prerm
. These scripts can then call qlist
to create a file containing the package file content which is then passed on to cvechecker
.
~$ cat /etc/portage/bashrc
if [ -x "/etc/portage/bashrc.d/package.${EBUILD_PHASE}" ];
then
source "/etc/portage/bashrc.d/package.${EBUILD_PHASE}"
fi
~$ cat /etc/portage/bashrc.d/package.prerm
TMPFILE=$(mktemp);
[ ! -f "${TMPFILE}" ] && die "Cannot create temporary file.";
qlist ${CATEGORY}/${P} > "${TMPFILE}";
cvechecker -D -b "${TMPFILE}";
rm "${TMPFILE}";
The cvechecker command will also accept standard input for the --binlist (-b) option when the minus sign is used:
~$ find /usr/bin -type f | cvechecker -b -
Searching for known software titles...
- Found match for /proc/version: cpe:/o:linux:linux_kernel:3.10.5-hardened:::
Make cvechecker output the matching CVE entries. A standard output might look like this:
~$ cvechecker -r
File "/usr/bin/kbxutil" (CPE = cpe:/a:gnupg:gnupg:2.0.15:::) on host localhost (key localhost)
Potential vulnerability found (CVE-2010-2547)
Full vulnerability match (incl. edition/language)
File "/usr/bin/gpgsm" (CPE = cpe:/a:gnupg:gnupg:2.0.15:::) on host localhost (key localhost)
Potential vulnerability found (CVE-2010-2547)
Full vulnerability match (incl. edition/language)
File "/usr/bin/watchgnupg" (CPE = cpe:/a:gnupg:gnupg:2.0.15:::) on host localhost (key localhost)
Potential vulnerability found (CVE-2010-2547)
Full vulnerability match (incl. edition/language)
However, if you would like to parse the output so that you can generate a better-looking report, ask cvechecker to use CSV output:
~$ cvechecker -r -C
Outputversion,File,CPE,CVE,Matchtype,Hostname,Userkey
2,/usr/bin/kbxutil,cpe:/a:gnupg:gnupg:2.0.15:::,CVE-2010-2547,1,localhost,localhost
2,/usr/bin/gpgsm,cpe:/a:gnupg:gnupg:2.0.15:::,CVE-2010-2547,1,localhost,localhost
2,/usr/bin/watchgnupg,cpe:/a:gnupg:gnupg:2.0.15:::,CVE-2010-2547,1,localhost,localhost
The default behavior of cvechecker
is to only report on those CVEs who specifically target the software and version you have installed. However, you might want to be informed about software matches for CVEs that affect higher versions than the versions installed on your system. Not all CVEs contain a full list of all versions affected but rather mention only the highest version vulnerable. The default reporting within cvechecker
wouldn't be triggered when this is the case, but if you add -H
or --reporthigher
, cvechecker
will also report on higher versions.
You can use the cvechecker output to generate a report. Within the cvechecker distribution, sample reporting files are available that show you a simple method. Of course, reporting is not part of this tools' goals; the primary purpose of this step is to show you that the output can indeed be used for reporting purposes. To facilitate (simple) reporting, a cvereport script has been provided which uses the sample reports currently. In the future, this will be enhanced with distribution-specific checks.
~$ cvereport -d /home/john/cvereport-20100902/ /home/john/cvechecker/acknowledgements.xml
The default report will use the default cvechecker
report. If you want to report using higher version matches as well, use -D
instead of -d
.
Below is a sample acknowledgements XML file. Its use should be self-explanatory:
<?xml version="1.0" encoding="UTF-8"?>
<acknowledgements>
<!-- I chose to use the CVE number as id for the resolution/comment text, but this is not mandatory -->
<resolution id="CVE-2008-4101">Has been solved by security update #17 (vim-1.7-b3)</resolution>
<comment id="CVE-2010-2547">Under investigation, bug opened on distributions bug site (#332329)</comment>
<!-- The @comment or @resolution should refer to one of the above descriptions.
Its use however is optional (you don't need to give comments) -->
<file name="/usr/bin/kbxutil" cve="CVE-2010-2547" state="acknowledged" comment="CVE-2010-2547" />
<file name="/usr/bin/vim" cve="CVE-2008-4101" state="irrelevant" resolution="CVE-2008-4101" />
</acknowledgements>
The final document (report.html) can then be mailed, published or in any other way sent to you.
If the report shows new CVE entries matching your system, investigate those CVE entries by first acknowledging and, if necessary, either update the software on your system or mark the entry as irrelevant.
The tool also supports listing the detected software/version on your system. This allows you to verify if the tool can detect the software you want to track CVE reports of.
~$ cvechecker -s
Detected vendor="wpa_supplicant", product="wpa_supplicant", version="0.6.10", update="", edition="", language="" on host="localhost", userkey="localhost"
...
You can also request the list of files that were used by cvechecker to identify the software:
~$ cvechecker -S
Detected vendor="wpa_supplicant", product="wpa_supplicant", version="0.6.10", update="", edition="", language="" on host="localhost", userkey="localhost"
Files that contributed to this detection:
- /usr/sbin/wpa_supplicant
- /usr/bin/wpa_cli
These options also support the -C switch (to enable CSV-like output for easier parsing);
~$ cvechecker -S -C
Outputversion,Vendor,Product,Version,Update,Edition,Language,Hostname,Userkey,Files
2,wpa_supplicant,wpa_supplicant,0.6.10,,,,localhost,localhost,/usr/sbin/wpa_supplicant /usr/bin/wpa_cli
With cvechecker, you can also "pretend" to have particular software (or hardware or operating systems) installed on your system. By feeding this so-called watchlist to cvechecker, it will add these titles to the database and assume they are also installed on the system.
An example watchlist is given next. Right now, the cvechecker application requires at least 8 fields so a number of trailing field separators might be needed. The example shows a watchlist for two applications:
~$ cat watchlist.txt
cpe:/a:dropbear_ssh_project:dropbear_ssh:2016.74:::
cpe:/a:libexpat:expat:2.2.0:::
It is recommended to use the watch lists simultaneously with the binary file listing. If you use it separately, don't forget to use the delta options. Otherwise, all detected software versions will be cleared from the database.
~$ cvechecker -b binlist.txt -w watchlist.txt
~$ cvechecker -w watchlist.txt --deltaonly
The cvechecker tool uses a configuration file to find out where to store its intermediate and final data (such as downloaded XML files, CSV files, database files).
The tool first looks for the configuration file pointed towards by the CVECHECKER_CONFFILE variable. If that environment variable doesn't exist, then .cvechecker.rc inside the users' home directory is looked for. If it can't find it, it will look for /usr/local/etc/cvechecker.conf and, if that file doesn't exist either, /etc/cvechecker.conf.
The cvechecker configuration file currently requires 6 configuration items:
#
# Generic settings
#
dbtype = "mysql";
#dbtype = "sqlite3";
cvecache = "/var/lib/cvechecker/cache";
datadir = "/usr/share/cvechecker";
stringcmd = "/usr/bin/strings -n 3 '@file@'";
version_url = "https://raw.github.com/sjvermeu/cvechecker/master/versions.dat";
#userkey = "servertag";
#
# For SQLite3
#
sqlite3: {
localdb = "/var/lib/cvechecker/local";
globaldb = "/var/lib/cvechecker/global.db";
}
#
# For MySQL
#
mysql: {
dbname = "cvechecker";
dbuser = "cvechecker_rw";
dbpass = "passwordforcvechecker_rw";
dbhost = "mysql.company.com";
};
These items describe the following resources:
dbtype tells the cvechecker application which back-end to use. Currently, "sqlite", "sqlite3" and "mysql" are supported (sqlite and sqlite3 result in the same back-end)
cvecache is a (cvechecker writeable) directory where pullcves will download all XML files and store the transformed XML2CSV files (containing the CVE entry data). Although it is not used anymore after being imported into the local databases, pullcves relies on the availability of the XML files to find out if it needs to (re)download and import CVE entries. So if you want to clean out the directory, make (empty) files named after the XML files so that pullcves does not redownload and reimport the CVE entry data (not that this will render the application unusable, but it takes a while)
datadir is a directory where cvechecker-related files are stored, including the XSLT transformation files used to convert CVE XML files in CSV files as well as the sample reporting files as used in this document
stringcmd is the command that cvechecker launches against a file to get the files' content. Currently, this is the only supported method for cvechecker to identify the software/version.
version_url is the location where pullcves can find the latest software/version matching rules to identify installed software on the system.
userkey is an optional setting which is used for server-side RDBMS support. When set, the data is stored with this particular key (next to the systems' hostname) as owner. This allows for multiple cvechecker runs on the same system (hostname + userkey) with different usages, but also to map cvechecker runs in larger organizations with that systems server tag/serial number/asset tag.
If not set, userkey is set to the hostname of the system (so data is owned by "hostname + hostname").
sqlite3: combines all sqlite specific settings, which are:
localdb is a (cvechecker writeable) directory where cvechecker will store its sqlite3 databases containing the CPE data (identification information of software/versions) as well as the local systems' matching file/software pairs and all downloaded CVE entries
globaldb is a (cvechecker writeable) sqlite3 database containing the software/version matching rules and CPEs associated with these rules
mysql: combines all mysql specific settings, which are:
dbname is the name of the cvechecker database
dbuser is the user that cvechecker uses to connect to the database
dbpass is the password that cvechecker uses to connect to the database and authenticate itself
dbhost is the hostname where the database resides
Warning
If you need to change parameters, make sure that the file containing the changed values contains all configuration directives (and not just the changed one). cvechecker does not "fall back" to other configuration files if a parameter is missing.
When you use cvechecker with MySQL, then the following sections might be of use to you...
When using MySQL database(s), it is recommended to use two separate roles:
The cvechecker administrative role should have the rights to SELECT, INSERT, UPDATE and DELETE data from tb_versionmatch, tb_cve, tb_cpe, tb_cpe_versions, tb_cpe_parents, tb_binmatch and tb_systems
The cvechecker operational role should have the rights to
SELECT, INSERT, UPDATE and DELETE data from tb_binmatch
SELECT and INSERT data into tb_cpe, tb_cpe_versions and tb_cpe_parents
SELECT data from tb_cve and tb_binmatch
If the database supports row-level security, you can configure the operational role on tb_binmatch with the additional security setting of "WHERE HOSTNAME='hostname' AND USERDEFKEY='userdefkey'" where hostname and userdefkey are the clients' hostname and userdefined key (userkey) setting (which defaults to the hostname again if no userkey is set).
A third role "could" be created (which allows cvechecker to (re)initialize its databases using cvechecker -i
) but this should only be activated during the (re)initialization and locked again when the change is finished.
The cvechecker tool currently uses InnoDB tables. The main (only) reason for this is that the tool uses foreign key definitions to keep referential integrity within the database. However, untrained administrators might find InnoDB a lot slower to work with than MyISAM. It is perfectly possible to use MyISAM tables instead of InnoDB (cvechecker does not use the cascading delete functionality within foreign key definitions):
Change the mysql_cvechecker.sql file by removing all references to FOREIGN KEY ... statements as well as ENGINE=InnoDB.
Load the (changed) SQL file in the MySQL database
Do not use cvechecker -i (as that runs hardcoded SQL statements which will transition to InnoDB again).
If you want to convert when data is already present, the easiest method in my opinion is to dump the information to a .sql file, change the .sql file and load it back in. However, other methods exist as well - which ones I leave as an excercise in Internet search engines for those interested ;-)
The software matching rules, as identified inside the versions.dat file, is pulled in and imported in the cvechecker database by pullcves.
The syntax of the versions.dat file is as follows:
,[filestart],1,[fileexpression],[contentexpression],[ao],[vendor],[product],[version],[update],[edition],[language]
The first comma is also used to inform cvechecker about the used column separator. If by any chance a field requires a comma as content, another separator can be chosen - just start the line with the chosen separator character.
The other fields have the following description:
filestart is a substring used by cvechecker to quickly find possible matches. A filename that starts with filestart will be considered for further evaluation.
1 is used to inform cvechecker about the used version matching methodology. Currently only 1 is supported and means that it uses the strings command output.
fileexpression is a regular expression used by cvechecker to find out if the file really needs to be scanned. Usually, the expression is just the filename, but for some binaries (like perl5.8.8) or libraries (like libconfig.so.1.2.8) having a matching regular expression allows cvechecker to identify these files as being part of a supported match-rule
contentexpression is a regular expression used against the strings command output to find (and obtain) the version, update, edition and language of the software. It uses regular expression groups to obtain the necessary information
'a' or 'o' tells cvechecker if the detected software is an application (a) or operating system (o)
vendor tells cvechecker what the vendor is of the file
product tells cvechecker what the product is to which the file belongs
version tells cvechecker what the detected version is of the product
update, if applicable, tells cvechecker the specific update of the software
edition, if applicable, tells cvechecker the specific edition of the software
language, if applicable, tells cvechecker the specific language of the software
The parts starting from the [ao] field are also known as the CPE or Common Platform Enumeration. See http://cpe.mitre.org for more information.
Some example lines are:
,gzip,1,gzip,^([0-9]\.[0-9][0-9]*),a,gnu,gzip,\1,,,
,vim,1,vim,VIM - Vi IMproved ([0-9\.]+) ,a,vim,vim,\1,,,
,ncftp,1,ncftp,^.*NcFTP ([0-9\.]+)/([0-9]+) .*,a,ncftp_software,ncftp,\1,\2,,
To validate the matching rules, you can ask cvechecker to tell you if, and what CPE data it detects from a specific file:
~$ cvechecker -f /usr/bin/vim
- Found match for /urs/bin/vim: cpe:/a:vim:vim:7.2:::
In the above case, it detected for the /usr/bin/vim file vim (product) from vim (vendor) versino 7.2. It was not able to deduce any specific releases/edition/language (but that is not mandatory anyway).
If you want to add additional rules, make sure that the dat-file you will be importing contains the previous rules as well - cvechecker will drop all previous rules while importing new ones.
~$ cvechecker -l /usr/local/var/cvechecker/cache/versions.dat
Loading in new version data file...
The version matching rules are at the core of the cvechecker
tool. Without them, the tool is not able to detect much of anything on your system. To allow you to contribute to the version matching rules, the project also contains a tool called cverules
.
The cverules
command, which currently only supports Gentoo systems but should be easily portable towards other distributions or even platforms, will attempt to generate version matching rules for cvechecker that are currently not part of the project but which should give additional matches on your system.
For instance, if cvechecker currently doesn't know how to detect OpenLDAP versions, but you have OpenLDAP on your system, then cverules
might be able to deduce a (generic put working) expression for the version matching rules which will allow cvechecker to identify OpenLDAP. If you then send the output of the cverules
to the cvechecker project, then these additional rules will be added to the version matching rules so that your next pullcves pull
will pull in these additional rules.