Alvlt's picture
Deploy CVE prediction API
ac704e3
Raw
History Blame Contribute Delete
4.88 kB
"""
features.py
Extracting and Cleaning Data from the NVD API
"""
import logging
from datetime import datetime
# We are in a .py so we dont't use 'print' but 'logger'
logger = logging.getLogger(__name__)
def extract_features(cve: dict) -> dict:
"""
Function to extract and clean data from the NVD API
Args:
cve: The NVD API returns a dictionary containing the raw CVE.
Returns:
Non-nested dictionary ready for model training
returns 'None' if the CVE dictionary is invalid.
"""
cve_id = cve["cve"]["id"]
published = cve["cve"]["published"]
# '.get' to provide a fallback in case the data is missing
source_identifier = cve["cve"].get("sourceIdentifier")
vulnerability_status = cve["cve"].get("vulnStatus")
description = cve["cve"].get("descriptions", [])
# Our model cannot read a description
# But a detailed—and therefore lengthy—description indicates a well-documented vulnerability, which makes it more vulnerable
description_words = " ".join([d.get("value", "") for d in description if d.get("lang") == "en"])
description_length = len(description_words)
reference = cve["cve"].get("references", [])
# metrics:
# security, if the metrics are missing:
metrics = cve["cve"].get("metrics", {})
weaknesses = cve["cve"].get("weaknesses", [])
cvss_v31 = metrics.get("cvssMetricV31", []) # "cvssMetricV31" is a list
cvss_data = cvss_v31[0]["cvssData"] if cvss_v31 else {}
configurations_data = cve["cve"].get("configurations", [])
base_score = cvss_data.get("baseScore")
attack_vector = cvss_data.get("attackVector")
attack_complexity = cvss_data.get("attackComplexity")
privileges_required = cvss_data.get("privilegesRequired")
user_interaction = cvss_data.get("userInteraction")
confidentiality_impact = cvss_data.get("confidentialityImpact")
integrity_impact = cvss_data.get("integrityImpact")
availability_impact = cvss_data.get("availabilityImpact")
# We are adding back these two metrics, which had been excluded due to probable collinearity
exploitability_score = cvss_v31[0].get("exploitabilityScore") if cvss_v31 else None
impact_score = cvss_v31[0].get("impactScore") if cvss_v31 else None
# addition of content type to weakness
# empty dictionary if there is no dictionary
weakness_data = weaknesses[0] if weaknesses else {}
description_list = weakness_data.get("description", [])
# Empty dictionary if no elements
description_data = description_list[0] if description_list else {}
cwe = description_data.get("value")
# Adding scope
scope = cvss_data.get("scope")
# Adding configuration
# Directory tree up to "criteria"
config_0 = configurations_data[0] if configurations_data else {}
nodes = config_0.get("nodes", [])
node_0 = nodes[0] if nodes else {}
cpe_matches = node_0.get("cpeMatch", [])
cpe_0 = cpe_matches[0] if cpe_matches else {}
criteria = cpe_0.get("criteria")
criteria_parts = criteria.split(":") if criteria else []
# If there is an application, hardware, OS
component_type = criteria_parts[2] if len(criteria_parts) > 2 else None
# The vendor
vendor = criteria_parts[3] if len(criteria_parts) > 3 else None
# Date
publication_date = datetime.strptime(published, "%Y-%m-%dT%H:%M:%S.%f") # %f for milliseconds
age_in_days = (datetime.now() - publication_date).days
reference_count = len(reference)
# We're looking for websites that contain code capable of exploiting vulnerabilities, such as exploit-db.com or GitHub
# If “exploits” are published on these sites, the likelihood of being hacked is much higher
has_exploit_reference = any (
"exploit" in ref.get("url", "") or "github" in ref.get("url", "")
for ref in reference
)
return {
"cve_id": cve_id,
"published": published,
"source_identifier": source_identifier,
"vulnerability_status": vulnerability_status,
"description_length" : description_length,
"description_words" : description_words,
"base_score": base_score,
"attack_vector": attack_vector,
"attack_complexity": attack_complexity,
"privileges_required": privileges_required,
"user_interaction": user_interaction,
"confidentiality_impact": confidentiality_impact,
"integrity_impact": integrity_impact,
"availability_impact": availability_impact,
"age_in_days": age_in_days,
"reference_count": reference_count,
"has_exploit_reference": has_exploit_reference,
"cwe": cwe,
"scope": scope,
"component_type": component_type,
"vendor": vendor,
"exploitability_score": exploitability_score,
"impact_score": impact_score
}