8000 Add a basic model for Known Exploited Vulnerabilities by ziadhany · Pull Request #1422 · aboutcode-org/vulnerablecode · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add a basic model for Known Exploited Vulnerabilities #1422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions vulnerabilities/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from rest_framework.throttling import UserRateThrottle

from vulnerabilities.models import Alias
from vulnerabilities.models import Kev
from vulnerabilities.models import Package
from vulnerabilities.models import Vulnerability
from vulnerabilities.models import VulnerabilityReference
Expand Down Expand Up @@ -167,6 +168,12 @@ def to_representation(self, instance):
return representation


class KEVSerializer(serializers.ModelSerializer):
class Meta:
model = Kev
fields = ["date_added", "description", "required_action", "due_date", "resources_and_notes"]


class VulnerabilitySerializer(BaseResourceSerializer):
fixed_packages = MinimalPackageSerializer(
many=True, source="filtered_fixed_packages", read_only=True
Expand All @@ -175,6 +182,7 @@ class VulnerabilitySerializer(BaseResourceSerializer):

references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set")
aliases = AliasSerializer(many=True, source="alias")
kev = KEVSerializer(read_only=True)
weaknesses = WeaknessSerializer(many=True)

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

kev = data.get("kev", None)
if not kev:
data.pop("kev")

return data

class Meta:
Expand All @@ -196,6 +208,7 @@ class Meta:
"affected_packages",
"references",
"weaknesses",
"kev",
]


Expand Down
2 changes: 2 additions & 0 deletions vulnerabilities/improvers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#

from vulnerabilities.improvers import valid_versions
from vulnerabilities.improvers import vulnerability_kev
from vulnerabilities.improvers import vulnerability_status

IMPROVERS_REGISTRY = [
Expand All @@ -27,6 +28,7 @@
valid_versions.RubyImprover,
valid_versions.GithubOSVImprover,
vulnerability_status.VulnerabilityStatusImprover,
vulnerability_kev.VulnerabilityKevImprover,
]

IMPROVERS_REGISTRY = {x.qualified_name: x for x in IMPROVERS_REGISTRY}
66 changes: 66 additions & 0 deletions vulnerabilities/improvers/vulnerability_kev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import logging
from typing import Iterable

from django.db.models import QuerySet
from sphinx.util import requests

from vulnerabilities.improver import Improver
from vulnerabilities.improver import Inference
from vulnerabilities.models import Advisory
from vulnerabilities.models import Alias
from vulnerabilities.models import Kev

logger = logging.getLogger(__name__)


class VulnerabilityKevImprover(Improver):
"""
Known Exploited Vulnerabilities Improver
"""

@property
def interesting_advisories(self) -> QuerySet:
# TODO Modify KEV improver to iterate over the vulnerabilities alias, not the advisory
return [Advisory.objects.first()]

def get_inferences(self, advisory_data) -> Iterable[Inference]:
"""
Fetch Kev data, iterate over it to find the vulnerability with the specified alias, and create or update
the Kev instance accordingly.
"""

kev_url = (
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
)
response = requests.get(kev_url)
kev_data = response.json()
if response.status_code != 200:
logger.error(
f"Failed to fetch the CISA Catalog of Known Exploited Vulnerabilities: {kev_url}"
)
return []

for kev_vul in kev_data.get("vulnerabilities", []):
alias = Alias.objects.get_or_none(alias=kev_vul["cveID"])
if not alias:
continue

vul = alias.vulnerability

if not vul:
continue

Kev.objects.update_or_create(
vulnerability=vul,
defaults={
"description": kev_vul["shortDescription"],
"date_added": kev_vul["dateAdded"],
"required_action": kev_vul["requiredAction"],
"due_date": kev_vul["dueDate"],
"resources_and_notes": kev_vul["notes"],
"known_ransomware_campaign_use": True
if kev_vul["knownRansomwareCampaignUse"] == "Known"
else False,
},
)
return []
72 changes: 72 additions & 0 deletions vulnerabilities/migrations/0057_kev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Generated by Django 4.1.13 on 2024-05-29 19:14

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("vulnerabilities", "0056_alter_packagechangelog_software_version_and_more"),
]

operations = [
migrations.CreateModel(
name="Kev",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
(
"date_added",
models.DateField(
blank=True,
help_text="The date the vulnerability was added to the Known Exploited Vulnerabilities (KEV) catalog in the format YYYY-MM-DD.",
null=True,
),
),
(
"description",
models.TextField(
help_text="Description of the vulnerability in the Known Exploited Vulnerabilities (KEV) catalog, usually a refinement of the original CVE description"
),
),
(
"required_action",
models.TextField(
help_text="The required action to address the vulnerability, typically to apply vendor updates or apply vendor mitigations or to discontinue use."
),
),
(
"due_date",
models.DateField(
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."
),
),
(
"resources_and_notes",
models.TextField(
help_text="Additional notes and resources about the vulnerability, often a URL to vendor instructions."
),
),
(
" 6D4E known_ransomware_campaign_use",
models.BooleanField(
default=False,
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.",
),
),
(
"vulnerability",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="kev",
to="vulnerabilities.vulnerability",
),
),
],
),
]
52 changes: 50 additions & 2 deletions vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,6 @@ class Meta:


class ChangeLog(models.Model):

action_time = models.DateTimeField(
# check if dates are actually UTC
default=timezone.now,
Expand Down Expand Up @@ -1261,7 +1260,6 @@ def log_action(self, package, action_type, actor_name, source_url, related_vulne


class PackageChangeLog(ChangeLog):

AFFECTED_BY = 1
FIXING = 2

Expand Down Expand Up @@ -1309,3 +1307,53 @@ def log_fixing(cls, package, importer, source_url, related_vulnerability):
source_url=source_url,
related_vulnerability=related_vulnerability,
)


class Kev(models.Model):
"""
Known Exploited Vulnerabilities
"""

vulnerability = models.OneToOneField(
Vulnerability,
on_delete=models.CASCADE,
related_name="kev",
)

date_added = models.DateField(
help_text="The date the vulnerability was added to the Known Exploited Vulnerabilities"
" (KEV) catalog in the format YYYY-MM-DD.",
null=True,
blank=True,
)

description = models.TextField(
help_text="Description of the vulnerability in the Known Exploited Vulnerabilities"
" (KEV) catalog, usually a refinement of the original CVE description"
)

required_action = models.TextField(
help_text="The required action to address the vulnerability, typically to "
"apply vendor updates or apply vendor mitigations or to discontinue use."
)

due_date = models.DateField(
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."
)

resources_and_notes = models.TextField(
help_text="Additional notes and resources about the vulnerability,"
" often a URL to vendor instructions."
)

known_ransomware_campaign_use = models.BooleanField(
default=False,
help_text="""Known if this vulnerability is known to have been leveraged as part of a ransomware campaign;
or 'Unknown' if CISA lacks confirmation that the vulnerability has been utilized for ransomware.""",
F438 )

@property
def get_known_ransomware_campaign_use_type(self):
return "Known" if self.known_ransomware_campaign_use else "Unknown"
90 changes: 90 additions & 0 deletions vulnerabilities/templates/vulnerability_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@
</span>
</a>
</li>
{% if vulnerability.kev %}<li data-tab="known-exploited-vulnerabilities">
<a>
<span>
Known Exploited Vulnerabilities
</span>
</a>
</li>{% endif %}
<li data-tab="history">
<a>
<span>
Expand Down Expand Up @@ -374,6 +381,89 @@
</tr>
{% endfor %}
</div>
{% if vulnerability.kev %}
<div class="tab-div content" data-content="known-exploited-vulnerabilities">
<div class="has-text-weight-bold tab-nested-div ml-1 mb-1 mt-1">
Known Exploited Vulnerabilities
</div>
<table class="table vcio-table width-100-pct mt-2">
<tbody>
<tr>
<td class="two-col-left">
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
data-tooltip="'Known' if this vulnerability is known to have been leveraged as part of a ransomware campaign; 'Unknown' if CISA lacks confirmation that the vulnerability has been utilized for ransomware">
Known Ransomware Campaign Use:
</span>
</td>
<td class="two-col-right">{{ vulnerability.kev.get_known_ransomware_campaign_use_type }}</td>
</tr>

{% if vulnerability.kev.description %}
<tr>
<td class="two-col-left">
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
data-tooltip="Description of the vulnerability in the Known Exploited Vulnerabilities
(KEV) catalog, usually a refinement of the original CVE description.">
Description:
</span>
</td>
<td class="two-col-right">{{ vulnerability.kev.description }}</td>
</tr>
{% endif %}
{% if vulnerability.kev.required_action %}
<tr>
<td class="two-col-left">
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
data-tooltip="The required action to address the vulnerability">
Required Action:
</span>
</td>
<td class="two-col-right">{{ vulnerability.kev.required_action }}</td>
</tr>
{% endif %}

{% if vulnerability.kev.resources_and_notes %}
<tr>
<td class="two-col-left">
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
data-tooltip="Any additional notes about the vulnerability">
Notes:
</span>
</td>
<td class="two-col-right">{{ vulnerability.kev.resources_and_notes }}</td>
</tr>
{% endif %}

{% if vulnerability.kev.due_date %}
<tr>
<td class="two-col-left">
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
data-tooltip="The date the required action is due in the format YYYY-MM-DD">
Due Date:
</span>
</td>
<td class="two-col-right">{{ vulnerability.kev.due_date }}</td>
</tr>
{% endif %}
{% if vulnerability.kev.date_added %}
<tr>
<td class="two-col-left">
<span
class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
data-tooltip="The date vulnerability was added to the catalog in the format YYYY-MM-DD">
Date Added:
</span>
</td>
<td class="two-col-right">{{ vulnerability.kev.date_added }}</td>
</tr>
{% endif %}

</tbody>
</table>
{% endif %}

</div>

<div class="tab-div content" data-content="history">
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<thead>
Expand Down
Loading
Loading
0