Skip to content

Commit 17de178

Browse files
authored
Merge branch 'main' into main
2 parents dc007e2 + c311f73 commit 17de178

File tree

9 files changed

+367
-8
lines changed

9 files changed

+367
-8
lines changed

requirements.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ beautifulsoup4==4.10.0
1111
binaryornot==0.4.4
1212
black==22.3.0
1313
boolean.py==3.8
14-
certifi==2023.7.22
14+
certifi==2024.7.4
1515
cffi==1.15.0
1616
chardet==4.0.0
1717
charset-normalizer==2.0.12
@@ -36,15 +36,15 @@ freezegun==1.2.1
3636
frozenlist==1.3.0
3737
gitdb==4.0.9
3838
GitPython==3.1.41
39-
gunicorn==20.1.0
39+
gunicorn==22.0.0
4040
idna==3.3
4141
imagesize==1.3.0
4242
importlib-metadata==4.11.3
4343
iniconfig==1.1.1
4444
ipython==8.10.0
4545
isort==5.10.1
4646
jedi==0.18.1
47-
Jinja2==3.1.3
47+
Jinja2==3.1.4
4848
jsonschema==3.2.0
4949
license-expression==21.6.14
5050
lxml==4.9.1
@@ -81,7 +81,7 @@ python-dateutil==2.8.2
8181
python-dotenv==0.20.0
8282
pytz==2022.1
8383
PyYAML==6.0.1
84-
requests==2.31.0
84+
requests==2.32.0
8585
restructuredtext-lint==1.4.0
8686
saneyaml==0.6.0
8787
semantic-version==2.9.0
@@ -98,7 +98,7 @@ sphinxcontrib-htmlhelp==2.0.0
9898
sphinxcontrib-jsmath==1.0.1
9999
sphinxcontrib-qthelp==1.0.3
100100
sphinxcontrib-serializinghtml==1.1.5
101-
sqlparse==0.4.4
101+
sqlparse==0.5.0
102102
stack-data==0.2.0
103103
stevedore==3.5.0
104104
texttable==1.6.4
@@ -111,7 +111,7 @@ urllib3==1.26.19
111111
wcwidth==0.2.5
112112
websocket-client==0.59.0
113113
yarl==1.7.2
114-
zipp==3.8.0
114+
zipp==3.19.1
115115
dateparser==1.1.1
116116
fetchcode==0.3.0
117117
cwe2==2.0.0

vulnerabilities/api.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from rest_framework.throttling import UserRateThrottle
2626

2727
from vulnerabilities.models import Alias
28+
from vulnerabilities.models import Kev
2829
from vulnerabilities.models import Package
2930
from vulnerabilities.models import Vulnerability
3031
from vulnerabilities.models import VulnerabilityReference
@@ -167,6 +168,12 @@ def to_representation(self, instance):
167168
return representation
168169

169170

171+
class KEVSerializer(serializers.ModelSerializer):
172+
class Meta:
173+
model = Kev
174+
fields = ["date_added", "description", "required_action", "due_date", "resources_and_notes"]
175+
176+
170177
class VulnerabilitySerializer(BaseResourceSerializer):
171178
fixed_packages = MinimalPackageSerializer(
172179
many=True, source="filtered_fixed_packages", read_only=True
@@ -175,6 +182,7 @@ class VulnerabilitySerializer(BaseResourceSerializer):
175182

176183
references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set")
177184
aliases = AliasSerializer(many=True, source="alias")
185+
kev = KEVSerializer(read_only=True)
178186
weaknesses = WeaknessSerializer(many=True)
179187

180188
def to_representation(self, instance):
@@ -183,6 +191,10 @@ def to_representation(self, instance):
183191
weaknesses = data.get("weaknesses", [])
184192
data["weaknesses"] = [weakness for weakness in weaknesses if weakness is not None]
185193

194+
kev = data.get("kev", None)
195+
if not kev:
196+
data.pop("kev")
197+
186198
return data
187199

188200
class Meta:
@@ -196,6 +208,7 @@ class Meta:
196208
"affected_packages",
197209
"references",
198210
"weaknesses",
211+
"kev",
199212
]
200213

201214

vulnerabilities/improvers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#
99

1010
from vulnerabilities.improvers import valid_versions
11+
from vulnerabilities.improvers import vulnerability_kev
1112
from vulnerabilities.improvers import vulnerability_status
1213

1314
IMPROVERS_REGISTRY = [
@@ -27,6 +28,7 @@
2728
valid_versions.RubyImprover,
2829
valid_versions.GithubOSVImprover,
2930
vulnerability_status.VulnerabilityStatusImprover,
31+
vulnerability_kev.VulnerabilityKevImprover,
3032
]
3133

3234
IMPROVERS_REGISTRY = {x.qualified_name: x for x in IMPROVERS_REGISTRY}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import logging
2+
from typing import Iterable
3+
4+
from django.db.models import QuerySet
5+
from sphinx.util import requests
6+
7+
from vulnerabilities.improver import Improver
8+
from vulnerabilities.improver import Inference
9+
from vulnerabilities.models import Advisory
10+
from vulnerabilities.models import Alias
11+
from vulnerabilities.models import Kev
12+
13+
logger = logging.getLogger(__name__)
14+
15+
16+
class VulnerabilityKevImprover(Improver):
17+
"""
18+
Known Exploited Vulnerabilities Improver
19+
"""
20+
21+
@property
22+
def interesting_advisories(self) -> QuerySet:
23+
# TODO Modify KEV improver to iterate over the vulnerabilities alias, not the advisory
24+
return [Advisory.objects.first()]
25+
26+
def get_inferences(self, advisory_data) -> Iterable[Inference]:
27+
"""
28+
Fetch Kev data, iterate over it to find the vulnerability with the specified alias, and create or update
29+
the Kev instance accordingly.
30+
"""
31+
32+
kev_url = (
33+
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
34+
)
35+
response = requests.get(kev_url)
36+
kev_data = response.json()
37+
if response.status_code != 200:
38+
logger.error(
39+
f"Failed to fetch the CISA Catalog of Known Exploited Vulnerabilities: {kev_url}"
40+
)
41+
return []
42+
43+
for kev_vul in kev_data.get("vulnerabilities", []):
44+
alias = Alias.objects.get_or_none(alias=kev_vul["cveID"])
45+
if not alias:
46+
continue
47+
48+
vul = alias.vulnerability
49+
50+
if not vul:
51+
continue
52+
53+
Kev.objects.update_or_create(
54+
vulnerability=vul,
55+
defaults={
56+
"description": kev_vul["shortDescription"],
57+
"date_added": kev_vul["dateAdded"],
58+
"required_action": kev_vul["requiredAction"],
59+
"due_date": kev_vul["dueDate"],
60+
"resources_and_notes": kev_vul["notes"],
61+
"known_ransomware_campaign_use": True
62+
if kev_vul["knownRansomwareCampaignUse"] == "Known"
63+
else False,
64+
},
65+
)
66+
return []
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Generated by Django 4.1.13 on 2024-05-29 19:14
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("vulnerabilities", "0056_alter_packagechangelog_software_version_and_more"),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name="Kev",
16+
fields=[
17+
(
18+
"id",
19+
models.AutoField(
20+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
21+
),
22+
),
23+
(
24+
"date_added",
25+
models.DateField(
26+
blank=True,
27+
help_text="The date the vulnerability was added to the Known Exploited Vulnerabilities (KEV) catalog in the format YYYY-MM-DD.",
28+
null=True,
29+
),
30+
),
31+
(
32+
"description",
33+
models.TextField(
34+
help_text="Description of the vulnerability in the Known Exploited Vulnerabilities (KEV) catalog, usually a refinement of the original CVE description"
35+
),
36+
),
37+
(
38+
"required_action",
39+
models.TextField(
40+
help_text="The required action to address the vulnerability, typically to apply vendor updates or apply vendor mitigations or to discontinue use."
41+
),
42+
),
43+
(
44+
"due_date",
45+
models.DateField(
46+
help_text="The date the required action is due in the format YYYY-MM-DD,which applies to all USA federal civilian executive branch (FCEB) agencies,but all organizations are strongly encouraged to execute the required action."
47+
),
48+
),
49+
(
50+
"resources_and_notes",
51+
models.TextField(
52+
help_text="Additional notes and resources about the vulnerability, often a URL to vendor instructions."
53+
),
54+
),
55+
(
56+
"known_ransomware_campaign_use",
57+
models.BooleanField(
58+
default=False,
59+
help_text="Known if this vulnerability is known to have been leveraged as part of a ransomware campaign; \n or 'Unknown' if CISA lacks confirmation that the vulnerability has been utilized for ransomware.",
60+
),
61+
),
62+
(
63+
"vulnerability",
64+
models.OneToOneField(
65+
on_delete=django.db.models.deletion.CASCADE,
66+
related_name="kev",
67+
to="vulnerabilities.vulnerability",
68+
),
69+
),
70+
],
71+
),
72+
]

vulnerabilities/models.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,6 @@ class Meta:
11211121

11221122

11231123
class ChangeLog(models.Model):
1124-
11251124
action_time = models.DateTimeField(
11261125
# check if dates are actually UTC
11271126
default=timezone.now,
@@ -1261,7 +1260,6 @@ def log_action(self, package, action_type, actor_name, source_url, related_vulne
12611260

12621261

12631262
class PackageChangeLog(ChangeLog):
1264-
12651263
AFFECTED_BY = 1
12661264
FIXING = 2
12671265

@@ -1309,3 +1307,53 @@ def log_fixing(cls, package, importer, source_url, related_vulnerability):
13091307
source_url=source_url,
13101308
related_vulnerability=related_vulnerability,
13111309
)
1310+
1311+
1312+
class Kev(models.Model):
1313+
"""
1314+
Known Exploited Vulnerabilities
1315+
"""
1316+
1317+
vulnerability = models.OneToOneField(
1318+
Vulnerability,
1319+
on_delete=models.CASCADE,
1320+
related_name="kev",
1321+
)
1322+
1323+
date_added = models.DateField(
1324+
help_text="The date the vulnerability was added to the Known Exploited Vulnerabilities"
1325+
" (KEV) catalog in the format YYYY-MM-DD.",
1326+
null=True,
1327+
blank=True,
1328+
)
1329+
1330+
description = models.TextField(
1331+
help_text="Description of the vulnerability in the Known Exploited Vulnerabilities"
1332+
" (KEV) catalog, usually a refinement of the original CVE description"
1333+
)
1334+
1335+
required_action = models.TextField(
1336+
help_text="The required action to address the vulnerability, typically to "
1337+
"apply vendor updates or apply vendor mitigations or to discontinue use."
1338+
)
1339+
1340+
due_date = models.DateField(
1341+
help_text="The date the required action is due in the format YYYY-MM-DD,"
1342+
"which applies to all USA federal civilian executive branch (FCEB) agencies,"
1343+
"but all organizations are strongly encouraged to execute the required action."
1344+
)
1345+
1346+
resources_and_notes = models.TextField(
1347+
help_text="Additional notes and resources about the vulnerability,"
1348+
" often a URL to vendor instructions."
1349+
)
1350+
1351+
known_ransomware_campaign_use = models.BooleanField(
1352+
default=False,
1353+
help_text="""Known if this vulnerability is known to have been leveraged as part of a ransomware campaign;
1354+
or 'Unknown' if CISA lacks confirmation that the vulnerability has been utilized for ransomware.""",
1355+
)
1356+
1357+
@property
1358+
def get_known_ransomware_campaign_use_type(self):
1359+
return "Known" if self.known_ransomware_campaign_use else "Unknown"

0 commit comments

Comments
 (0)