|
1 | 1 | import json
|
2 | 2 | import logging
|
3 | 3 | import re
|
4 |
| -from datetime import datetime |
5 | 4 | from pathlib import Path
|
6 | 5 | from typing import Iterable
|
7 |
| -from typing import List |
8 |
| -from typing import Optional |
9 | 6 |
|
10 | 7 | import dateparser
|
11 |
| -from packageurl import PackageURL |
12 |
| -from univers.version_constraint import VersionConstraint |
13 |
| -from univers.version_range import RANGE_CLASS_BY_SCHEMES |
14 |
| -from univers.version_range import VersionRange |
15 |
| -from univers.versions import AlpineLinuxVersion |
16 |
| -from univers.versions import ArchLinuxVersion |
17 |
| -from univers.versions import ComposerVersion |
18 |
| -from univers.versions import DebianVersion |
19 |
| -from univers.versions import GenericVersion |
20 |
| -from univers.versions import GentooVersion |
21 |
| -from univers.versions import GolangVersion |
22 |
| -from univers.versions import InvalidVersion |
23 |
| -from univers.versions import LegacyOpensslVersion |
24 |
| -from univers.versions import MavenVersion |
25 |
| -from univers.versions import NginxVersion |
26 |
| -from univers.versions import NugetVersion |
27 |
| -from univers.versions import OpensslVersion |
28 |
| -from univers.versions import PypiVersion |
29 |
| -from univers.versions import RpmVersion |
30 |
| -from univers.versions import SemverVersion |
31 |
| -from univers.versions import Version |
32 | 8 |
|
33 | 9 | from vulnerabilities.importer import AdvisoryData
|
34 |
| -from vulnerabilities.importer import AffectedPackage |
35 | 10 | from vulnerabilities.importer import Importer
|
36 | 11 | from vulnerabilities.importer import Reference
|
37 | 12 | from vulnerabilities.importer import VulnerabilitySeverity
|
38 | 13 | from vulnerabilities.severity_systems import SCORING_SYSTEMS
|
39 |
| -from vulnerabilities.utils import build_description |
40 |
| -from vulnerabilities.utils import dedupe |
41 | 14 | from vulnerabilities.utils import get_advisory_url
|
42 | 15 | from vulnerabilities.utils import get_cwe_id
|
43 | 16 |
|
44 | 17 | logger = logging.getLogger(__name__)
|
45 | 18 |
|
46 |
| -VULNRICH_VERSION_CLASS_SCHEMES = { |
47 |
| - "semver": SemverVersion, |
48 |
| - "python": PypiVersion, |
49 |
| - "custom": GenericVersion, |
50 |
| - "rpm": RpmVersion, |
51 |
| - "maven": MavenVersion, |
52 |
| -} |
53 |
| - |
54 | 19 |
|
55 | 20 | class VulnrichImporter(Importer):
|
56 | 21 | spdx_license_expression = "CC0-1.0"
|
@@ -88,76 +53,14 @@ def parse_cve_advisory(raw_data, advisory_url):
|
88 | 53 | state = cve_metadata.get("state")
|
89 | 54 |
|
90 | 55 | date_published = cve_metadata.get("datePublished")
|
91 |
| - date_published = dateparser.parse(date_published) |
| 56 | + if date_published: |
| 57 | + date_published = dateparser.parse(date_published) |
92 | 58 |
|
93 | 59 | # Extract containers
|
94 | 60 | containers = raw_data.get("containers", {})
|
95 | 61 | cna_data = containers.get("cna", {})
|
96 | 62 | adp_data = containers.get("adp", {})
|
97 | 63 |
|
98 |
| - # Extract affected products |
99 |
| - affected_packages = [] |
100 |
| - for affected_product in cna_data.get("affected", []): |
101 |
| - if type(affected_product) != dict: |
102 |
| - continue |
103 |
| - cpes = affected_product.get("cpes") # TODO Add references cpes |
104 |
| - |
105 |
| - vendor = affected_product.get("vendor") or "" |
106 |
| - collection_url = affected_product.get("collectionURL") or "" |
107 |
| - product = affected_product.get("product") or "" |
108 |
| - package_name = affected_product.get("packageName") or "" |
109 |
| - |
110 |
| - platforms = affected_product.get("platforms", []) |
111 |
| - default_status = affected_product.get("defaultStatus") |
112 |
| - |
113 |
| - affected_packages = [] |
114 |
| - # purl (vendor, collection_url, product, package_name, platforms) |
115 |
| - purl = PackageURL( |
116 |
| - type=vendor, |
117 |
| - name=product, |
118 |
| - namespace=package_name, |
119 |
| - ) |
120 |
| - |
121 |
| - versions = affected_product.get("versions", []) |
122 |
| - for version_data in versions: |
123 |
| - # version ≤ V ≤ (lessThanOrEqual/lessThan) |
124 |
| - # right_version ≤ V ≤ left_version |
125 |
| - version_constraints = [] |
126 |
| - r_version = version_data.get("version") |
127 |
| - version_type = version_data.get("versionType") |
128 |
| - version_class = VULNRICH_VERSION_CLASS_SCHEMES.get(version_type) |
129 |
| - if not version_class: |
130 |
| - logger.error(f"Invalid version_class type: {version_type}") |
131 |
| - continue |
132 |
| - |
133 |
| - l_version, l_comparator = None, "" |
134 |
| - if "lessThan" in version_data: |
135 |
| - l_version = version_data.get("lessThan") |
136 |
| - l_comparator = "<" |
137 |
| - elif "lessThanOrEqual" in version_data: |
138 |
| - l_version = version_data.get("lessThanOrEqual") |
139 |
| - l_comparator = "<=" |
140 |
| - try: |
141 |
| - if l_version and l_comparator: |
142 |
| - version_constraints.append( |
143 |
| - VersionConstraint(comparator=l_comparator, version=version_class(l_version)) |
144 |
| - ) |
145 |
| - if r_version: |
146 |
| - version_constraints.append( |
147 |
| - VersionConstraint(comparator=">", version=version_class(r_version)) |
148 |
| - ) |
149 |
| - except InvalidVersion: |
150 |
| - logger.error(f"InvalidVersion: {l_version}-{r_version}") |
151 |
| - continue |
152 |
| - |
153 |
| - affected_packages.append( |
154 |
| - AffectedPackage( |
155 |
| - purl, |
156 |
| - affected_version_range=VersionRange(constraints=version_constraints), |
157 |
| - ) |
158 |
| - ) |
159 |
| - status = version_data.get("status") |
160 |
| - |
161 | 64 | # Extract descriptions
|
162 | 65 | summary = ""
|
163 | 66 | description_list = cna_data.get("descriptions", [])
|
@@ -204,35 +107,49 @@ def parse_cve_advisory(raw_data, advisory_url):
|
204 | 107 | )
|
205 | 108 | severities.append(severity)
|
206 | 109 |
|
207 |
| - # Extract references |
| 110 | + # Extract references cpes and ignore affected products |
| 111 | + cpes = set() |
| 112 | + for affected_product in cna_data.get("affected", []): |
| 113 | + if type(affected_product) != dict: |
| 114 | + continue |
| 115 | + cpes.update(affected_product.get("cpes") or []) # TODO Add references cpes |
| 116 | + |
208 | 117 | # TODO ADD reference type
|
209 | 118 | references = [
|
210 | 119 | Reference(url=ref.get("url"), severities=severities)
|
211 | 120 | for ref in cna_data.get("references", [])
|
212 | 121 | ]
|
213 | 122 |
|
214 |
| - weaknesses = [] |
| 123 | + cpes_ref = [ |
| 124 | + Reference( |
| 125 | + reference_id=cpe, |
| 126 | + url=f"https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query={cpe}", |
| 127 | + ) |
| 128 | + for cpe in sorted(list(cpes)) |
| 129 | + ] |
| 130 | + references.extend(cpes_ref) |
| 131 | + |
| 132 | + weaknesses = set() |
215 | 133 | for problem_type in cna_data.get("problemTypes", []):
|
216 | 134 | descriptions = problem_type.get("descriptions", [])
|
217 | 135 | for description in descriptions:
|
218 | 136 | cwe_id = description.get("cweId")
|
219 | 137 | if cwe_id:
|
220 |
| - weaknesses.append(get_cwe_id(cwe_id)) |
| 138 | + weaknesses.add(get_cwe_id(cwe_id)) |
221 | 139 |
|
222 | 140 | description_text = description.get("description")
|
223 | 141 | if description_text:
|
224 |
| - pattern = r"CWE-(\d{3})" |
| 142 | + pattern = r"CWE-(\d+)" |
225 | 143 | match = re.search(pattern, description_text)
|
226 | 144 | if match:
|
227 |
| - weaknesses.append(match.group(1)) |
| 145 | + weaknesses.add(int(match.group(1))) |
228 | 146 |
|
229 | 147 | return AdvisoryData(
|
230 | 148 | aliases=[cve_id],
|
231 | 149 | summary=summary,
|
232 |
| - affected_packages=affected_packages, |
233 | 150 | references=references,
|
234 |
| - # date_published=dateparser.parse(self.cve_item.get("publishedDate")), |
235 |
| - weaknesses=weaknesses, |
| 151 | + date_published=date_published, |
| 152 | + weaknesses=list(weaknesses), |
236 | 153 | url=advisory_url,
|
237 | 154 | )
|
238 | 155 |
|
|
0 commit comments