Skip to content

Commit 952e33f

Browse files
authored
Merge pull request #200 from sbs2001/debian_oval_importer
Add Debian OVAL importer
2 parents e194649 + 5c13ce6 commit 952e33f

8 files changed

Lines changed: 437 additions & 1 deletion

File tree

vulnerabilities/data_source.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,8 @@ def get_data_from_xml_doc(self, xml_doc: ET.ElementTree, pkg_metadata={}) -> Lis
479479
for test_data in definition_data['test_data']:
480480
for package in test_data['package_list']:
481481
pkg_name = package
482+
if package and len(pkg_name) >= 50:
483+
continue
482484
aff_ver_range = test_data['version_ranges']
483485
all_versions = self.pkg_manager_api.get(package)
484486
# This filter is for filtering out long versions.

vulnerabilities/import_runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def _get_or_create_vulnerability(advisory: Advisory) -> Tuple[models.Vulnerabili
160160

161161

162162
def _get_or_create_package(p: PackageURL) -> Tuple[models.Package, bool]:
163-
version = packageurl.normalize_version(p.version, encode=True)
163+
version = p.version
164164

165165
query_kwargs = {
166166
'name': packageurl.normalize_name(p.name, p.type, encode=True),

vulnerabilities/importers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@
3131
from vulnerabilities.importers.ubuntu import UbuntuDataSource
3232
from vulnerabilities.importers.retiredotnet import RetireDotnetDataSource
3333
from vulnerabilities.importers.suse_backports import SUSEBackportsDataSource
34+
from vulnerabilities.importers.debian_oval import DebianOvalDataSource
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
4+
# Data generated with VulnerableCode require an acknowledgment.
5+
#
6+
# You may not use this software except in compliance with the License.
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
12+
#
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
15+
#
16+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
19+
# for any legal advice.
20+
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
21+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
22+
23+
24+
import asyncio
25+
import dataclasses
26+
from typing import Iterable
27+
from typing import List
28+
from typing import Mapping
29+
from typing import Set
30+
import xml.etree.ElementTree as ET
31+
32+
33+
from aiohttp import ClientSession
34+
from aiohttp.client_exceptions import ClientResponseError, ServerDisconnectedError
35+
import requests
36+
37+
38+
from vulnerabilities.data_source import OvalDataSource, DataSourceConfiguration
39+
40+
41+
@dataclasses.dataclass
42+
class DebianOvalConfiguration(DataSourceConfiguration):
43+
releases: list
44+
etags: dict
45+
46+
47+
class DebianOvalDataSource(OvalDataSource):
48+
49+
CONFIG_CLASS = DebianOvalConfiguration
50+
51+
def __init__(self, *args, **kwargs):
52+
super().__init__(*args, **kwargs)
53+
# we could avoid setting translations, and have it
54+
# set by default in the OvalParser, but we don't yet know
55+
# whether all OVAL providers use the same format
56+
self.translations = {'less than': '<'}
57+
self.pkg_manager_api = VersionAPI()
58+
59+
def _fetch(self):
60+
base_url = 'https://www.debian.org/security/oval/'
61+
file_name = 'oval-definitions-{}.xml'
62+
releases = self.config.releases
63+
for release in releases:
64+
file_url = base_url + file_name.format(release)
65+
if not self.create_etag(file_url):
66+
continue
67+
resp = requests.get(file_url).content
68+
yield (
69+
{'type': 'deb', 'namespace': 'debian',
70+
'qualifiers': {'distro': release}
71+
},
72+
ET.ElementTree(ET.fromstring(resp.decode('utf-8')))
73+
)
74+
return []
75+
76+
def set_api(self, packages):
77+
asyncio.run(self.pkg_manager_api.load_api(packages))
78+
79+
def create_etag(self, url):
80+
etag = requests.head(url).headers.get('ETag')
81+
if not etag:
82+
return True
83+
elif url in self.config.etags:
84+
if self.config.etags[url] == etag:
85+
return False
86+
self.config.etags[url] = etag
87+
return True
88+
89+
90+
class VersionAPI:
91+
def __init__(self, cache: Mapping[str, Set[str]] = None):
92+
self.cache = cache or {}
93+
94+
def get(self, package_name: str) -> Set[str]:
95+
return self.cache[package_name]
96+
97+
async def load_api(self, pkg_set):
98+
# Need to set the headers, because the Debian API upgrades
99+
# the connection to HTTP 2.0
100+
async with ClientSession(
101+
raise_for_status=True,
102+
headers={'Connection': 'keep-alive'}
103+
) as session:
104+
await asyncio.gather(*[self.set_api(pkg, session)
105+
for pkg in pkg_set if pkg not in self.cache])
106+
107+
async def set_api(self, pkg, session, retry_count=5):
108+
if pkg in self.cache:
109+
return
110+
url = ('https://sources.debian.org/api/src/{}'.format(pkg))
111+
try:
112+
all_versions = set()
113+
response = await session.request(method='GET', url=url)
114+
resp_json = await response.json()
115+
116+
if resp_json.get('error') or not resp_json.get('versions'):
117+
self.cache[pkg] = {}
118+
return
119+
for release in resp_json['versions']:
120+
all_versions.add(release['version'])
121+
122+
self.cache[pkg] = all_versions
123+
# TODO : Handle ServerDisconnectedError by using some sort of
124+
# retry mechanism
125+
except (ClientResponseError, asyncio.exceptions.TimeoutError, ServerDisconnectedError):
126+
self.cache[pkg] = {}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
4+
# Data generated with VulnerableCode require an acknowledgment.
5+
#
6+
# You may not use this software except in compliance with the License.
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
12+
#
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
15+
#
16+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
19+
# for any legal advice.
20+
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
21+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
22+
23+
from django.db import migrations
24+
25+
26+
def add_debian_oval_importer(apps, _):
27+
Importer = apps.get_model('vulnerabilities', 'Importer')
28+
29+
Importer.objects.create(
30+
name='debian_oval',
31+
license='',
32+
last_run=None,
33+
data_source='DebianOvalDataSource',
34+
data_source_cfg={'releases':['wheezy','stretch','jessie','buster'],
35+
'etags':{}},
36+
)
37+
38+
39+
def remove_debian_oval_importer(apps, _):
40+
Importer = apps.get_model('vulnerabilities', 'Importer')
41+
qs = Importer.objects.filter(name='debian_oval')
42+
if qs:
43+
qs[0].delete()
44+
45+
46+
class Migration(migrations.Migration):
47+
48+
dependencies = [
49+
('vulnerabilities', '0011_susebackports_importer'),
50+
]
51+
52+
operations = [
53+
migrations.RunPython(add_debian_oval_importer, remove_debian_oval_importer),
54+
]

vulnerabilities/oval_parser.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def get_data(self) -> List[Dict]:
5757
definition_data = {'test_data': []}
5858
definition_data['description'] = definition.getMetadata(
5959
).getDescription() # this could use some data cleaning
60+
61+
if not definition_data['description']:
62+
definition_data['description'] = ''
63+
6064
definition_data['vuln_id'] = self.get_vuln_id_from_definition(
6165
definition)
6266
definition_data['reference_urls'] = self.get_urls_from_definition(
@@ -166,6 +170,9 @@ def get_urls_from_definition(definition: OvalDefinition) -> Set[str]:
166170

167171
@staticmethod
168172
def get_vuln_id_from_definition(definition):
173+
# SUSE and Ubuntu OVAL files will get cves via this loop
169174
for child in definition.element.iter():
170175
if child.get('ref_id'):
171176
return child.get('ref_id')
177+
# Debian OVAL files will get cves via this
178+
return definition.getMetadata().getTitle()
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?xml version='1.0' encoding='utf-8'?>
2+
<oval_definitions xmlns:ind-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xmlns:linux-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5" xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:unix-def="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5" xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd">
3+
<generator>
4+
<oval:product_name>Debian</oval:product_name>
5+
<oval:schema_version>5.11.2</oval:schema_version>
6+
<oval:timestamp>2020-06-08T23:31:02.188-04:00</oval:timestamp>
7+
</generator>
8+
<definitions>
9+
<definition class="vulnerability" id="oval:org.debian:def:20011593" version="1">
10+
<metadata>
11+
<title>CVE-2001-1593</title>
12+
<affected family="unix">
13+
<platform>Debian GNU/Linux 7</platform>
14+
<product>a2ps</product>
15+
</affected>
16+
<description>security update</description>
17+
<debian>
18+
<date>2014-03-31</date>
19+
<moreinfo>
20+
DSA-2892
21+
Several vulnerabilities have been found in a2ps, an &lt;q&gt;Anything to
22+
PostScript&lt;/q&gt; converter and pretty-printer. The Common Vulnerabilities and
23+
Exposures project identifies the following problems:
24+
The spy_user function which is called when a2ps is invoked with the
25+
--debug flag insecurely used temporary files.
26+
Brian M. Carlson reported that a2ps's fixps script does not invoke
27+
gs with the -dSAFER option. Consequently executing fixps on a
28+
malicious PostScript file could result in files being deleted or
29+
arbitrary commands being executed with the privileges of the user
30+
running fixps.
31+
</moreinfo>
32+
</debian>
33+
</metadata>
34+
<criteria comment="Release section" operator="AND">
35+
<criterion comment="Debian 7 is installed" test_ref="oval:org.debian.oval:tst:1"/>
36+
<criteria comment="Architecture section" operator="OR">
37+
<criteria comment="Architecture independent section" operator="AND">
38+
<criterion comment="all architecture" test_ref="oval:org.debian.oval:tst:2"/>
39+
<criterion comment="a2ps DPKG is earlier than 1:4.14-1.1+deb7u1" test_ref="oval:org.debian.oval:tst:3"/>
40+
</criteria>
41+
</criteria>
42+
</criteria>
43+
</definition>
44+
<definition class="vulnerability" id="oval:org.debian:def:20022443" version="1">
45+
<metadata>
46+
<title>CVE-2002-2443</title>
47+
<affected family="unix">
48+
<platform>Debian GNU/Linux 7</platform>
49+
<product>krb5</product>
50+
</affected>
51+
<description>denial of service</description>
52+
<debian>
53+
<date>2013-05-29</date>
54+
<moreinfo>
55+
DSA-2701
56+
It was discovered that the kpasswd service running on UDP port 464
57+
could respond to response packets, creating a packet loop and a denial
58+
of service condition.
59+
</moreinfo>
60+
</debian>
61+
</metadata>
62+
<criteria comment="Release section" operator="AND">
63+
<criterion comment="Debian 7 is installed" test_ref="oval:org.debian.oval:tst:1"/>
64+
<criteria comment="Architecture section" operator="OR">
65+
<criteria comment="Architecture independent section" operator="AND">
66+
<criterion comment="all architecture" test_ref="oval:org.debian.oval:tst:2"/>
67+
<criterion comment="krb5 DPKG is earlier than 1.10.1+dfsg-5+deb7u1" test_ref="oval:org.debian.oval:tst:4"/>
68+
</criteria>
69+
</criteria>
70+
</criteria>
71+
</definition>
72+
</definitions>
73+
74+
<tests>
75+
<textfilecontent54_test check="all" check_existence="at_least_one_exists" comment="Debian GNU/Linux 7 is installed" id="oval:org.debian.oval:tst:1" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent">
76+
<object object_ref="oval:org.debian.oval:obj:1"/>
77+
<state state_ref="oval:org.debian.oval:ste:1"/>
78+
</textfilecontent54_test>
79+
80+
<uname_test check="all" check_existence="at_least_one_exists" comment="Installed architecture is all" id="oval:org.debian.oval:tst:2" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix">
81+
<object object_ref="oval:org.debian.oval:obj:2"/>
82+
</uname_test>
83+
<dpkginfo_test check="all" check_existence="at_least_one_exists" comment="a2ps is earlier than 1:4.14-1.1+deb7u1" id="oval:org.debian.oval:tst:3" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
84+
<object object_ref="oval:org.debian.oval:obj:3"/>
85+
<state state_ref="oval:org.debian.oval:ste:2"/>
86+
</dpkginfo_test>
87+
88+
<dpkginfo_test check="all" check_existence="at_least_one_exists" comment="krb5 is earlier than 1.10.1+dfsg-5+deb7u1" id="oval:org.debian.oval:tst:4" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
89+
<object object_ref="oval:org.debian.oval:obj:4"/>
90+
<state state_ref="oval:org.debian.oval:ste:3"/>
91+
</dpkginfo_test>
92+
93+
</tests>
94+
95+
<objects>
96+
97+
<textfilecontent54_object id="oval:org.debian.oval:obj:1" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent">
98+
<path>/etc</path>
99+
<filename>debian_version</filename>
100+
<pattern operation="pattern match">(\d+)\.\d</pattern>
101+
<instance datatype="int">1</instance>
102+
</textfilecontent54_object>
103+
104+
<uname_object id="oval:org.debian.oval:obj:2" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix"/>
105+
<dpkginfo_object id="oval:org.debian.oval:obj:3" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
106+
<name>a2ps</name>
107+
</dpkginfo_object>
108+
<dpkginfo_object id="oval:org.debian.oval:obj:4" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
109+
<name>krb5</name>
110+
</dpkginfo_object>
111+
112+
113+
</objects>
114+
115+
<states>
116+
<textfilecontent54_state id="oval:org.debian.oval:ste:1" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent">
117+
<subexpression operation="equals">7</subexpression>
118+
</textfilecontent54_state>
119+
<dpkginfo_state id="oval:org.debian.oval:ste:2" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
120+
<evr datatype="debian_evr_string" operation="less than">0:1:4.14-1.1+deb7u1</evr>
121+
</dpkginfo_state>
122+
<dpkginfo_state id="oval:org.debian.oval:ste:3" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
123+
<evr datatype="debian_evr_string" operation="less than">0:1.10.1+dfsg-5+deb7u1</evr>
124+
</dpkginfo_state>
125+
</states>
126+
127+
128+
</oval_definitions>

0 commit comments

Comments
 (0)