Skip to content

Commit

Permalink
fixed wrong results from cves for cpe
Browse files Browse the repository at this point in the history
  • Loading branch information
P-T-I committed Jul 5, 2021
1 parent 5850d27 commit b55fb34
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 12 deletions.
2 changes: 1 addition & 1 deletion CveXplore/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.4
0.2.5
73 changes: 73 additions & 0 deletions CveXplore/common/cpe_converters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
cpe_converters.py
=================
"""
from urllib.parse import unquote


def from2to3CPE(cpe, autofill=False):
"""
Method to transform cpe2.2 to cpe2.3 format
:param cpe: cpe2.2 string
:type cpe: str
:param autofill: Whether to cpe string should be autofilled with double quotes and hyphens
:type autofill: bool
:return: cpe2.3 formatted string
:rtype: str
"""
cpe = cpe.strip()
if not cpe.startswith("cpe:2.3:"):
if not cpe.startswith("cpe:/"):
# can not do anything with this; returning original string
return cpe
cpe = cpe.replace("cpe:/", "cpe:2.3:")
cpe = cpe.replace("::", ":-:")
cpe = cpe.replace("~-", "~")
cpe = cpe.replace("~", ":-:")
cpe = cpe.replace("::", ":")
cpe = cpe.strip(":-")
cpe = unquote(cpe)
if autofill:
e = cpe.split(":")
for x in range(0, 13 - len(e)):
cpe += ":*"
return cpe


def from3to2CPE(cpe):
"""
Method to transform cpe2.3 to cpe2.2 format
:param cpe: cpe2.3 string
:type cpe: str
:return: cpe2.2 string
:rtype: str
"""
cpe = cpe.strip()
if not cpe.startswith("cpe:/"):
if not cpe.startswith("cpe:2.3:"):
# can not do anything with this; returning original string
return cpe
cpe = cpe.replace("cpe:2.3:", "")
parts = cpe.split(":")
next = []
first = "cpe:/" + ":".join(parts[:5])
last = parts[5:]
if last:
for x in last:
next.append("~") if x == "-" else next.append(x)
if "~" in next:
pad(next, 6, "~")
cpe = "%s:%s" % (first, "".join(next))
cpe = cpe.replace(":-:", "::")
cpe = cpe.strip(":")
return cpe


def pad(seq, target_length, padding=None):
length = len(seq)
if length > target_length:
return seq
seq.extend([padding] * (target_length - length))
return seq
31 changes: 21 additions & 10 deletions CveXplore/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import functools
import json
import os
import re
from collections import defaultdict

from pymongo import DESCENDING

from CveXplore.api.connection.api_db import ApiDatabaseSource
from CveXplore.common.cpe_converters import from2to3CPE
from CveXplore.common.db_mapping import database_mapping
from CveXplore.database.connection.mongo_db import MongoDBConnection
from CveXplore.errors import DatabaseIllegalCollection
Expand Down Expand Up @@ -194,29 +196,38 @@ def get_multi_store_entries(self, *queries, limit=10):

return list(joined_list)

def cves_for_cpe(self, cpe_string, vuln_prod_search=False):
def cves_for_cpe(self, cpe_string):
"""
Method for retrieving Cves that match a single CPE string. By default the search will be made matching
the configuration fields of the cves documents.
:param cpe_string: CPE string: e.g. ``cpe:2.3:o:microsoft:windows_7:*:sp1:*:*:*:*:*:*``
:type cpe_string: str
:param vuln_prod_search: Search for matching products instead of configurations
:type vuln_prod_search: bool
:return: List with Cves
:rtype: list
"""

e = cpe_string.split(":")
for x in range(0, 13 - len(e)):
cpe_string += ":*"
# format to cpe2.3
cpe_string = from2to3CPE(cpe_string)

cpe = self.get_single_store_entry("cpe", {"cpe_2_2": cpe_string})
if cpe_string.startswith("cpe"):
# strict search with term starting with cpe; e.g: cpe:2.3:o:microsoft:windows_7:*:sp1:*:*:*:*:*:*

if cpe is not None:
return list(cpe.iter_cves_matching_cpe(vuln_prod_search))
remove_trailing_regex_stars = r"(?:\:|\:\:|\:\*)+$"

cpe_regex = re.escape(re.sub(remove_trailing_regex_stars, "", cpe_string))

cpe_regex_string = r"^{}:".format(cpe_regex)
else:
return cpe
# more general search on same field; e.g. microsoft:windows_7
cpe_regex_string = "{}".format(re.escape(cpe_string))

cves = self.get_single_store_entries(
("cves", {"vulnerable_configuration": {"$regex": cpe_regex_string}}),
limit=0,
)

return cves

def cve_by_id(self, cve_id):
"""
Expand Down
20 changes: 19 additions & 1 deletion CveXplore/objects/cpe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
cpe
===
"""
import re

from pymongo import DESCENDING

from CveXplore.common.cpe_converters import from2to3CPE
from CveXplore.common.data_source_connection import DatasourceConnection


Expand Down Expand Up @@ -34,8 +37,23 @@ def iter_cves_matching_cpe(self, vuln_prod_search=False):
"vulnerable_product" if vuln_prod_search else "vulnerable_configuration"
)

# format to cpe2.3
cpe_string = from2to3CPE(self.cpe_2_2)

if cpe_string.startswith("cpe"):
# strict search with term starting with cpe; e.g: cpe:2.3:o:microsoft:windows_7:*:sp1:*:*:*:*:*:*

remove_trailing_regex_stars = r"(?:\:|\:\:|\:\*)+$"

cpe_regex = re.escape(re.sub(remove_trailing_regex_stars, "", cpe_string))

cpe_regex_string = r"^{}:".format(cpe_regex)
else:
# more general search on same field; e.g. microsoft:windows_7
cpe_regex_string = "{}".format(re.escape(cpe_string))

results = self._datasource_connection.store_cves.find(
{cpe_searchField: self.cpe_2_2}
{cpe_searchField: {"$regex": cpe_regex_string}}
).sort("cvss", DESCENDING)

for each in results:
Expand Down

0 comments on commit b55fb34

Please sign in to comment.