mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-17 05:05:16 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,401 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
CVSS Vulnerability Prioritization Engine
|
||||
|
||||
Calculates CVSS v4.0 base scores, enriches with EPSS threat intelligence,
|
||||
and generates risk-weighted prioritization for vulnerability remediation.
|
||||
|
||||
Requirements:
|
||||
pip install requests pandas
|
||||
|
||||
Usage:
|
||||
python process.py score --cve CVE-2024-3094
|
||||
python process.py prioritize --csv vulns.csv --output prioritized.csv
|
||||
python process.py enrich --csv vulns.csv
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import math
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
import pandas as pd
|
||||
import requests
|
||||
|
||||
|
||||
class CVSSv4Calculator:
|
||||
"""CVSS v4.0 Base Score Calculator."""
|
||||
|
||||
# CVSS v4.0 metric value mappings
|
||||
METRIC_VALUES = {
|
||||
"AV": {"N": 0.0, "A": 0.1, "L": 0.2, "P": 0.3},
|
||||
"AC": {"L": 0.0, "H": 0.1},
|
||||
"AT": {"N": 0.0, "P": 0.1},
|
||||
"PR": {"N": 0.0, "L": 0.1, "H": 0.2},
|
||||
"UI": {"N": 0.0, "P": 0.1, "A": 0.2},
|
||||
"VC": {"H": 0.0, "L": 0.1, "N": 0.2},
|
||||
"VI": {"H": 0.0, "L": 0.1, "N": 0.2},
|
||||
"VA": {"H": 0.0, "L": 0.1, "N": 0.2},
|
||||
"SC": {"H": 0.0, "L": 0.1, "N": 0.2},
|
||||
"SI": {"H": 0.0, "L": 0.1, "N": 0.2},
|
||||
"SA": {"H": 0.0, "L": 0.1, "N": 0.2},
|
||||
}
|
||||
|
||||
# Severity thresholds
|
||||
SEVERITY_RATINGS = [
|
||||
(0.0, 0.0, "None"),
|
||||
(0.1, 3.9, "Low"),
|
||||
(4.0, 6.9, "Medium"),
|
||||
(7.0, 8.9, "High"),
|
||||
(9.0, 10.0, "Critical"),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def parse_vector(vector_string: str) -> dict:
|
||||
"""Parse a CVSS v4.0 vector string into metric components."""
|
||||
metrics = {}
|
||||
parts = vector_string.replace("CVSS:4.0/", "").replace("CVSS:3.1/", "").split("/")
|
||||
for part in parts:
|
||||
if ":" in part:
|
||||
key, value = part.split(":", 1)
|
||||
metrics[key] = value
|
||||
return metrics
|
||||
|
||||
@staticmethod
|
||||
def get_severity(score: float) -> str:
|
||||
"""Map a numeric CVSS score to its severity rating."""
|
||||
for low, high, rating in CVSSv4Calculator.SEVERITY_RATINGS:
|
||||
if low <= score <= high:
|
||||
return rating
|
||||
return "Unknown"
|
||||
|
||||
@classmethod
|
||||
def estimate_base_score(cls, vector_string: str) -> float:
|
||||
"""
|
||||
Estimate CVSS v4.0 base score from a vector string.
|
||||
Note: Full CVSS v4.0 scoring uses complex lookup tables from FIRST.
|
||||
This implements a simplified scoring approximation.
|
||||
"""
|
||||
metrics = cls.parse_vector(vector_string)
|
||||
|
||||
# Exploitability sub-score
|
||||
av = cls.METRIC_VALUES["AV"].get(metrics.get("AV", "N"), 0)
|
||||
ac = cls.METRIC_VALUES["AC"].get(metrics.get("AC", "L"), 0)
|
||||
at = cls.METRIC_VALUES["AT"].get(metrics.get("AT", "N"), 0)
|
||||
pr = cls.METRIC_VALUES["PR"].get(metrics.get("PR", "N"), 0)
|
||||
ui = cls.METRIC_VALUES["UI"].get(metrics.get("UI", "N"), 0)
|
||||
|
||||
exploitability = 1.0 - (av + ac + at + pr + ui) / 1.0
|
||||
|
||||
# Vulnerable system impact
|
||||
vc = cls.METRIC_VALUES["VC"].get(metrics.get("VC", "N"), 0.2)
|
||||
vi = cls.METRIC_VALUES["VI"].get(metrics.get("VI", "N"), 0.2)
|
||||
va = cls.METRIC_VALUES["VA"].get(metrics.get("VA", "N"), 0.2)
|
||||
|
||||
vuln_impact = 1.0 - (vc + vi + va) / 0.6
|
||||
|
||||
# Subsequent system impact
|
||||
sc = cls.METRIC_VALUES["SC"].get(metrics.get("SC", "N"), 0.2)
|
||||
si = cls.METRIC_VALUES["SI"].get(metrics.get("SI", "N"), 0.2)
|
||||
sa = cls.METRIC_VALUES["SA"].get(metrics.get("SA", "N"), 0.2)
|
||||
|
||||
subseq_impact = 1.0 - (sc + si + sa) / 0.6
|
||||
|
||||
# Combined impact (weighted)
|
||||
total_impact = 0.6 * vuln_impact + 0.4 * max(subseq_impact, 0)
|
||||
|
||||
if total_impact <= 0:
|
||||
return 0.0
|
||||
|
||||
# Approximate base score
|
||||
score = min(10.0, (exploitability * 4.0 + total_impact * 6.0))
|
||||
return round(score, 1)
|
||||
|
||||
|
||||
class VulnerabilityEnricher:
|
||||
"""Enrich vulnerability data with EPSS scores and CISA KEV status."""
|
||||
|
||||
NVD_API = "https://services.nvd.nist.gov/rest/json/cves/2.0"
|
||||
EPSS_API = "https://api.first.org/data/v1/epss"
|
||||
CISA_KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
||||
|
||||
def __init__(self):
|
||||
self.kev_cache = None
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update({"User-Agent": "CVSS-Prioritization-Tool/1.0"})
|
||||
|
||||
def get_nvd_data(self, cve_id: str) -> dict:
|
||||
"""Fetch CVE details from NVD API v2.0."""
|
||||
try:
|
||||
response = self.session.get(
|
||||
self.NVD_API, params={"cveId": cve_id}, timeout=30
|
||||
)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
vulns = data.get("vulnerabilities", [])
|
||||
if vulns:
|
||||
cve_data = vulns[0].get("cve", {})
|
||||
metrics = cve_data.get("metrics", {})
|
||||
|
||||
# Try CVSS v4.0 first, then v3.1
|
||||
cvss_data = {}
|
||||
if "cvssMetricV40" in metrics:
|
||||
m = metrics["cvssMetricV40"][0]["cvssData"]
|
||||
cvss_data = {
|
||||
"version": "4.0",
|
||||
"vector": m.get("vectorString", ""),
|
||||
"base_score": m.get("baseScore", 0),
|
||||
"severity": m.get("baseSeverity", ""),
|
||||
}
|
||||
elif "cvssMetricV31" in metrics:
|
||||
m = metrics["cvssMetricV31"][0]["cvssData"]
|
||||
cvss_data = {
|
||||
"version": "3.1",
|
||||
"vector": m.get("vectorString", ""),
|
||||
"base_score": m.get("baseScore", 0),
|
||||
"severity": m.get("baseSeverity", ""),
|
||||
}
|
||||
|
||||
descriptions = cve_data.get("descriptions", [])
|
||||
desc = next(
|
||||
(d["value"] for d in descriptions if d["lang"] == "en"),
|
||||
""
|
||||
)
|
||||
|
||||
return {
|
||||
"cve_id": cve_id,
|
||||
"description": desc[:300],
|
||||
"published": cve_data.get("published", ""),
|
||||
"cvss": cvss_data,
|
||||
}
|
||||
except Exception as e:
|
||||
print(f" [!] NVD API error for {cve_id}: {e}")
|
||||
return {}
|
||||
|
||||
def get_epss_score(self, cve_id: str) -> dict:
|
||||
"""Fetch EPSS score for a CVE from FIRST API."""
|
||||
try:
|
||||
response = self.session.get(
|
||||
self.EPSS_API, params={"cve": cve_id}, timeout=15
|
||||
)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get("data"):
|
||||
entry = data["data"][0]
|
||||
return {
|
||||
"epss_score": float(entry.get("epss", 0)),
|
||||
"epss_percentile": float(entry.get("percentile", 0)),
|
||||
}
|
||||
except Exception as e:
|
||||
print(f" [!] EPSS API error for {cve_id}: {e}")
|
||||
return {"epss_score": 0.0, "epss_percentile": 0.0}
|
||||
|
||||
def load_kev_catalog(self) -> set:
|
||||
"""Load CISA Known Exploited Vulnerabilities catalog."""
|
||||
if self.kev_cache is not None:
|
||||
return self.kev_cache
|
||||
|
||||
try:
|
||||
response = self.session.get(self.CISA_KEV_URL, timeout=30)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
self.kev_cache = {
|
||||
v["cveID"] for v in data.get("vulnerabilities", [])
|
||||
}
|
||||
print(f"[+] Loaded {len(self.kev_cache)} CVEs from CISA KEV catalog")
|
||||
return self.kev_cache
|
||||
except Exception as e:
|
||||
print(f"[!] Failed to load CISA KEV: {e}")
|
||||
self.kev_cache = set()
|
||||
return self.kev_cache
|
||||
|
||||
def is_in_kev(self, cve_id: str) -> bool:
|
||||
"""Check if a CVE is in the CISA KEV catalog."""
|
||||
kev = self.load_kev_catalog()
|
||||
return cve_id in kev
|
||||
|
||||
def enrich_cve(self, cve_id: str) -> dict:
|
||||
"""Fully enrich a CVE with NVD, EPSS, and KEV data."""
|
||||
result = {"cve_id": cve_id}
|
||||
|
||||
nvd = self.get_nvd_data(cve_id)
|
||||
if nvd:
|
||||
result.update({
|
||||
"description": nvd.get("description", ""),
|
||||
"published": nvd.get("published", ""),
|
||||
"cvss_version": nvd.get("cvss", {}).get("version", ""),
|
||||
"cvss_vector": nvd.get("cvss", {}).get("vector", ""),
|
||||
"cvss_base_score": nvd.get("cvss", {}).get("base_score", 0),
|
||||
"cvss_severity": nvd.get("cvss", {}).get("severity", ""),
|
||||
})
|
||||
|
||||
epss = self.get_epss_score(cve_id)
|
||||
result.update(epss)
|
||||
|
||||
result["in_cisa_kev"] = self.is_in_kev(cve_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class VulnerabilityPrioritizer:
|
||||
"""Risk-weighted vulnerability prioritization engine."""
|
||||
|
||||
def __init__(self, weights: dict = None):
|
||||
self.weights = weights or {
|
||||
"cvss": 0.25,
|
||||
"epss": 0.25,
|
||||
"asset_criticality": 0.20,
|
||||
"kev": 0.15,
|
||||
"exposure": 0.15,
|
||||
}
|
||||
|
||||
def calculate_priority_score(self, vuln: dict) -> float:
|
||||
"""Calculate composite priority score for a vulnerability."""
|
||||
cvss_score = float(vuln.get("cvss_base_score", 0)) / 10.0
|
||||
epss_score = float(vuln.get("epss_score", 0))
|
||||
asset_crit = float(vuln.get("asset_criticality", 3)) / 5.0
|
||||
kev_score = 1.0 if vuln.get("in_cisa_kev", False) else 0.0
|
||||
exposure = float(vuln.get("exposure_score", 3)) / 5.0
|
||||
|
||||
priority = (
|
||||
cvss_score * self.weights["cvss"] +
|
||||
epss_score * self.weights["epss"] +
|
||||
asset_crit * self.weights["asset_criticality"] +
|
||||
kev_score * self.weights["kev"] +
|
||||
exposure * self.weights["exposure"]
|
||||
)
|
||||
|
||||
return round(priority * 10, 2)
|
||||
|
||||
def assign_sla(self, priority_score: float, cvss_score: float,
|
||||
in_kev: bool = False) -> dict:
|
||||
"""Assign remediation SLA based on priority score."""
|
||||
if in_kev or priority_score >= 8.0:
|
||||
return {"level": "P1-Emergency", "sla_days": 2, "sla": "48 hours"}
|
||||
elif priority_score >= 6.5 or cvss_score >= 9.0:
|
||||
return {"level": "P2-Critical", "sla_days": 7, "sla": "7 days"}
|
||||
elif priority_score >= 5.0 or cvss_score >= 7.0:
|
||||
return {"level": "P3-High", "sla_days": 14, "sla": "14 days"}
|
||||
elif priority_score >= 3.0 or cvss_score >= 4.0:
|
||||
return {"level": "P4-Medium", "sla_days": 30, "sla": "30 days"}
|
||||
else:
|
||||
return {"level": "P5-Low", "sla_days": 90, "sla": "90 days"}
|
||||
|
||||
def prioritize(self, vulnerabilities: list) -> pd.DataFrame:
|
||||
"""Prioritize a list of vulnerabilities and return sorted DataFrame."""
|
||||
results = []
|
||||
for vuln in vulnerabilities:
|
||||
score = self.calculate_priority_score(vuln)
|
||||
sla = self.assign_sla(
|
||||
score,
|
||||
float(vuln.get("cvss_base_score", 0)),
|
||||
vuln.get("in_cisa_kev", False)
|
||||
)
|
||||
|
||||
results.append({
|
||||
**vuln,
|
||||
"priority_score": score,
|
||||
"priority_level": sla["level"],
|
||||
"sla_days": sla["sla_days"],
|
||||
"remediation_sla": sla["sla"],
|
||||
})
|
||||
|
||||
df = pd.DataFrame(results)
|
||||
df = df.sort_values("priority_score", ascending=False)
|
||||
return df
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="CVSS Vulnerability Prioritization Engine")
|
||||
subparsers = parser.add_subparsers(dest="command")
|
||||
|
||||
# Score a single CVE
|
||||
score_parser = subparsers.add_parser("score", help="Score and enrich a single CVE")
|
||||
score_parser.add_argument("--cve", required=True, help="CVE identifier (e.g., CVE-2024-3094)")
|
||||
|
||||
# Prioritize a CSV of vulnerabilities
|
||||
pri_parser = subparsers.add_parser("prioritize", help="Prioritize vulnerabilities from CSV")
|
||||
pri_parser.add_argument("--csv", required=True, help="Input CSV with cve_id column")
|
||||
pri_parser.add_argument("--output", required=True, help="Output CSV with priorities")
|
||||
|
||||
# Enrich a CSV with EPSS/KEV data
|
||||
enrich_parser = subparsers.add_parser("enrich", help="Enrich CVE list with EPSS and KEV")
|
||||
enrich_parser.add_argument("--csv", required=True, help="Input CSV with cve_id column")
|
||||
enrich_parser.add_argument("--output", default=None, help="Output enriched CSV")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "score":
|
||||
enricher = VulnerabilityEnricher()
|
||||
print(f"[*] Scoring {args.cve}...")
|
||||
|
||||
result = enricher.enrich_cve(args.cve)
|
||||
print(f"\n{'='*60}")
|
||||
print(f"CVE: {result.get('cve_id')}")
|
||||
print(f"Description: {result.get('description', 'N/A')[:200]}")
|
||||
print(f"Published: {result.get('published', 'N/A')}")
|
||||
print(f"CVSS Version: {result.get('cvss_version', 'N/A')}")
|
||||
print(f"CVSS Vector: {result.get('cvss_vector', 'N/A')}")
|
||||
print(f"CVSS Base Score: {result.get('cvss_base_score', 'N/A')}")
|
||||
print(f"CVSS Severity: {result.get('cvss_severity', 'N/A')}")
|
||||
print(f"EPSS Score: {result.get('epss_score', 0):.4f} ({result.get('epss_percentile', 0)*100:.1f}th percentile)")
|
||||
print(f"In CISA KEV: {'Yes' if result.get('in_cisa_kev') else 'No'}")
|
||||
|
||||
prioritizer = VulnerabilityPrioritizer()
|
||||
priority = prioritizer.calculate_priority_score(result)
|
||||
sla = prioritizer.assign_sla(
|
||||
priority, float(result.get("cvss_base_score", 0)),
|
||||
result.get("in_cisa_kev", False)
|
||||
)
|
||||
print(f"\nPriority Score: {priority}")
|
||||
print(f"Priority Level: {sla['level']}")
|
||||
print(f"Remediation SLA: {sla['sla']}")
|
||||
|
||||
elif args.command == "prioritize":
|
||||
df = pd.read_csv(args.csv)
|
||||
if "cve_id" not in df.columns:
|
||||
print("[-] CSV must contain 'cve_id' column")
|
||||
sys.exit(1)
|
||||
|
||||
enricher = VulnerabilityEnricher()
|
||||
enriched = []
|
||||
for _, row in df.iterrows():
|
||||
cve = row["cve_id"]
|
||||
print(f"[*] Processing {cve}...")
|
||||
data = enricher.enrich_cve(cve)
|
||||
data.update(row.to_dict())
|
||||
enriched.append(data)
|
||||
|
||||
prioritizer = VulnerabilityPrioritizer()
|
||||
result_df = prioritizer.prioritize(enriched)
|
||||
result_df.to_csv(args.output, index=False)
|
||||
print(f"\n[+] Prioritized results saved to: {args.output}")
|
||||
|
||||
print("\n=== Priority Summary ===")
|
||||
print(result_df["priority_level"].value_counts().to_string())
|
||||
|
||||
elif args.command == "enrich":
|
||||
df = pd.read_csv(args.csv)
|
||||
enricher = VulnerabilityEnricher()
|
||||
|
||||
enriched = []
|
||||
for _, row in df.iterrows():
|
||||
cve = row.get("cve_id", "")
|
||||
if cve:
|
||||
print(f"[*] Enriching {cve}...")
|
||||
data = enricher.enrich_cve(cve)
|
||||
data.update(row.to_dict())
|
||||
enriched.append(data)
|
||||
|
||||
result_df = pd.DataFrame(enriched)
|
||||
output = args.output or args.csv.replace(".csv", "_enriched.csv")
|
||||
result_df.to_csv(output, index=False)
|
||||
print(f"[+] Enriched data saved to: {output}")
|
||||
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user