Visions of CVE-IDs Dancing Before Your Eyes
The Common Vulnerabilities and Exposures (CVE) database provides an open catalog of vulnerabilities in software, each identified by a CVE-ID of the form CVE-2016-0001. This is a vital resource for the thankless task of keeping servers and applications patched up to date and as secure as possible. Failing to include some form of automated CVE check on your application software as a part of your build and release process, such as the OWASP Dependency-Check, leaves the door open to a whole range of avoidable and costly problems.
As a general rule, dependency checkers, like automated scanning tools that look for web application and network vulnerabilities, will produce output in every possible format except the one desired. Certainly the scanning tools don't make life easy for the people tasked with wading through a report and translating the results into actions. The reports are built with other audiences in mind, largely those who make the purchasing decisions. The only guarantee for a developer is that CVE-IDs will be listed in there somewhere.
The sorry state of vulnerability reports was an annoyance for developers at a company I'm presently working with. While putting in place better security processes, we found that the reports generated for legacy software were as much an impediment as a useful tool. Translating the output into something that developers, who may not be familiar with the ins and outs of web application security, could act on efficiently was a significant time sink for security team members. Thus I ended up writing a quick Node.js tool to ingest arbitrary text content, identify CVE-IDs, obtain data from the CVE database, and produce a CSV document that can be sorted by CVE severity rating. This is a much more helpful artifact than those produced by many scanning tools, sad to say. One of the pleasures of working with this company is that the technology team are very willing to open source the tools they produce along the way, and so you can find cve-tools at GitHub. It is easy to use:
npm install cve-tools cd node_modules/cve-tools # From a file. bin/create-cve-csv -f path/to/file > cves.csv # From a file via pipe. cat path/to/file | bin/create-cve-csv > cves.csv # Directly. bin/create-cve-csv \ "CVE-2015-0001 blah blah CVE-2015-0002, etc." > cves.csv # Directly via pipe. echo "CVE-2015-0001 blah blah CVE-2015-0002, etc." \ | bin/create-cve-csv > cves.csv
This is a simple piece of technology. The brief time taken to write it largely went into relearning everything I'd forgotten about parsing XML, and in a survey of the state of XML libraries in Node.js. If you spend much of your time working in the Node.js ecosystem, you might be forgiven for thinking that XML is vanished from the world, a dinosaur superseded by JSON, but this is in fact far from the case. Unfortunately, most of the Node.js XML packages are not so great. They are either not up to dealing with very complex XML, expose clunky interfaces, are micropackages to handle only a very small number of tasks relating to XML, or are far too slow. The only way to obtain fast enough and comprehensive enough XML processing in Node.js, and in a way that won't tax sanity, appears to be to use a package that both provides a thin interface to native code and supports XPath - which at present means using libxmljs.
Here is how to use libxmljs with the large CVE XML files from the National Vulnerability Database in order to extract the desired information. This simple operation is somewhat complicated by the gleeful and largely unnecessary use of namespaces for everything in these documents, but once over that hurdle XPath makes everything easy:
var fs = require('fs'); var util = require('util'); var libxmljs = require('libxmljs'); var xml = fs.readFileSync('/path/to/nvdcve-2.0-2015.xml', { encoding: 'utf8' } ); var doc = libxmljs.parseXml(xml); var cve = { id: 'CVE-2015-0500' }; // A URL reference for the CVE. cve.url = 'https://web.nvd.nist.gov/view/vuln/detail?vulnId=' + cve.id; // The NVD doc is overly namespaced. So we need this to get anything done // with XPath in libxmljs. var namespaceIds = { // Have to specify the default and give it an id to get libxmljs happy. n: 'http://scap.nist.gov/schema/feed/vulnerability/2.0', // Use the prefixes in the doc for the rest. 'cpe-lang': 'http://cpe.mitre.org/language/2.0', cvss: 'http://scap.nist.gov/schema/cvss-v2/0.2', patch: 'http://scap.nist.gov/schema/patch/0.1', 'scap-core': 'http://scap.nist.gov/schema/scap-core/0.1', vuln: 'http://scap.nist.gov/schema/vulnerability/0.4' }; var element = doc.find(util.format( '/n:nvd/n:entry[@id=\'%s\']', cve.id ), namespaceIds)[0]; if (!element) { throw new Error('Not present in NVD data.'); } // Get the vulnerability score. var cvssElement = elem.find( 'vuln:cvss/cvss:base_metrics/cvss:score', namespaceIds )[0]; if (cvssElement) { cve.cvss = cvssElement.text(); } // Get the summary. var summaryElement = elem.find('vuln:summary', namespaceIds)[0]; if (summaryElement) { cve.summary = summaryElement.text(); } // Print the result. console.info(cve);