From 1244af649dc3f34e92218943ecaa4b8425f0a677 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Tue, 9 Sep 2014 15:10:08 -0400 Subject: [PATCH] updated to improve CPE matching so that if a broad match occured (cpe with no version number) we use the highest confidence version when generating the CPE identifier Former-commit-id: 6e8c87a71522b1ca7cfa9d72ca419a792d1b17e7 --- .../dependencycheck/analyzer/CPEAnalyzer.java | 36 +++++++++++++------ .../analyzer/CPEAnalyzerIntegrationTest.java | 5 +-- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java index a9f069ca2..97779a515 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java @@ -182,9 +182,9 @@ public class CPEAnalyzer implements Analyzer { } /* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no * CPE identified. As such, we are "using" the evidence and ignoring the results. */ - if (dependency.getVersionEvidence().contains(confidence)) { - addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence); - } +// if (dependency.getVersionEvidence().contains(confidence)) { +// addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence); +// } if (!vendors.isEmpty() && !products.isEmpty()) { final List entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(), dependency.getVendorEvidence().getWeighting()); @@ -194,7 +194,7 @@ public class CPEAnalyzer implements Analyzer { if (verifyEntry(e, dependency)) { final String vendor = e.getVendor(); final String product = e.getProduct(); - identifierAdded |= determineIdentifiers(dependency, vendor, product); + identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence); } } if (identifierAdded) { @@ -492,12 +492,16 @@ public class CPEAnalyzer implements Analyzer { * @return true if an identifier was added to the dependency; otherwise false * @throws UnsupportedEncodingException is thrown if UTF-8 is not supported */ - private boolean determineIdentifiers(Dependency dependency, String vendor, String product) throws UnsupportedEncodingException { + private boolean determineIdentifiers(Dependency dependency, String vendor, String product, Confidence currentConfidence) throws UnsupportedEncodingException { final Set cpes = cve.getCPEs(vendor, product); DependencyVersion bestGuess = new DependencyVersion("-"); Confidence bestGuessConf = null; + boolean hasBroadMatch = false; final List collected = new ArrayList(); for (Confidence conf : Confidence.values()) { +// if (conf.compareTo(currentConfidence) > 0) { +// break; +// } for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) { final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue()); if (evVer == null) { @@ -510,9 +514,12 @@ public class CPEAnalyzer implements Analyzer { } else { dbVer = DependencyVersionUtil.parseVersion(vs.getVersion()); } - if (dbVer == null //special case, no version specified - everything is vulnerable - || evVer.equals(dbVer)) { //yeah! exact match - + if (dbVer == null) { //special case, no version specified - everything is vulnerable + hasBroadMatch = true; + final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8")); + final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf); + collected.add(match); + } else if (evVer.equals(dbVer)) { //yeah! exact match final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8")); final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf); collected.add(match); @@ -538,7 +545,11 @@ public class CPEAnalyzer implements Analyzer { } } final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString()); - final String url = null; + String url = null; + if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess. + final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product); + url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8")); + } if (bestGuessConf == null) { bestGuessConf = Confidence.LOW; } @@ -577,7 +588,12 @@ public class CPEAnalyzer implements Analyzer { /** * A best guess for the CPE. */ - BEST_GUESS + BEST_GUESS, + /** + * The entire vendor/product group must be added (without a guess at version) because there is a CVE with a VS + * that only specifies vendor/product. + */ + BROAD_MATCH } /** diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java index 277e25f4c..c54982eb8 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java @@ -89,6 +89,7 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase { FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer(); try { + callDetermineCPE_full("struts2-core-2.3.16.3.jar", "cpe:/a:apache:struts:2.3.16.3", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp); callDetermineCPE_full("hazelcast-2.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp); callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp); callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp); @@ -112,13 +113,9 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase { Dependency dep = new Dependency(file); fnAnalyzer.analyze(dep, null); - jarAnalyzer.analyze(dep, null); - hAnalyzer.analyze(dep, null); - instance.analyze(dep, null); - fp.analyze(dep, null); if (expResult != null) {