mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-03 01:10:18 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
---
|
||||
name: None
|
||||
description: The Common Vulnerability Scoring System (CVSS) is the industry standard framework maintained by FIRST (Forum of Incident Response and Security Teams) for assessing vulnerability severity. CVSS v4.0 (r
|
||||
domain: cybersecurity
|
||||
subdomain: vulnerability-management
|
||||
tags: [vulnerability-management, cve, cvss, risk, prioritization, nist]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: MIT
|
||||
---
|
||||
# Prioritizing Vulnerabilities with CVSS Scoring
|
||||
|
||||
## Overview
|
||||
The Common Vulnerability Scoring System (CVSS) is the industry standard framework maintained by FIRST (Forum of Incident Response and Security Teams) for assessing vulnerability severity. CVSS v4.0 (released November 2023) introduces refined metrics for more accurate scoring. This skill covers calculating CVSS scores, interpreting vector strings, and using CVSS alongside contextual factors like EPSS and CISA KEV for effective vulnerability prioritization.
|
||||
|
||||
## Prerequisites
|
||||
- Understanding of common vulnerability types (buffer overflow, injection, XSS, etc.)
|
||||
- Familiarity with networking concepts (attack vectors, protocols)
|
||||
- Access to NVD (National Vulnerability Database) for CVE lookups
|
||||
- Vulnerability scan results requiring prioritization
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### CVSS v4.0 Metric Groups
|
||||
|
||||
#### 1. Base Metrics (Intrinsic Severity)
|
||||
Represent the inherent characteristics of a vulnerability:
|
||||
|
||||
**Exploitability Metrics:**
|
||||
- **Attack Vector (AV)**: Network (N), Adjacent (A), Local (L), Physical (P)
|
||||
- **Attack Complexity (AC)**: Low (L), High (H)
|
||||
- **Attack Requirements (AT)**: None (N), Present (P) - NEW in v4.0
|
||||
- **Privileges Required (PR)**: None (N), Low (L), High (H)
|
||||
- **User Interaction (UI)**: None (N), Passive (P), Active (A) - Expanded in v4.0
|
||||
|
||||
**Impact Metrics (Vulnerable System):**
|
||||
- **Confidentiality (VC)**: None (N), Low (L), High (H)
|
||||
- **Integrity (VI)**: None (N), Low (L), High (H)
|
||||
- **Availability (VA)**: None (N), Low (L), High (H)
|
||||
|
||||
**Impact Metrics (Subsequent System):**
|
||||
- **Confidentiality (SC)**: None (N), Low (L), High (H)
|
||||
- **Integrity (SI)**: None (N), Low (L), High (H)
|
||||
- **Availability (SA)**: None (N), Low (L), High (H)
|
||||
|
||||
#### 2. Threat Metrics (Dynamic Context)
|
||||
- **Exploit Maturity (E)**: Attacked (A), POC (P), Unreported (U)
|
||||
|
||||
#### 3. Environmental Metrics (Organization-Specific)
|
||||
Modified versions of base metrics reflecting local deployment context, plus:
|
||||
- **Confidentiality Requirement (CR)**: High (H), Medium (M), Low (L)
|
||||
- **Integrity Requirement (IR)**: High (H), Medium (M), Low (L)
|
||||
- **Availability Requirement (AR)**: High (H), Medium (M), Low (L)
|
||||
|
||||
#### 4. Supplemental Metrics (Advisory Information)
|
||||
- **Safety (S)**: Present (P), Negligible (X)
|
||||
- **Automatable (AU)**: Yes (Y), No (N)
|
||||
- **Recovery (R)**: Automatic (A), User (U), Irrecoverable (I)
|
||||
- **Value Density (V)**: Diffuse (D), Concentrated (C)
|
||||
- **Vulnerability Response Effort (RE)**: Low (L), Moderate (M), High (H)
|
||||
- **Provider Urgency (U)**: Red, Amber, Green, Clear
|
||||
|
||||
### CVSS v4.0 Severity Ratings
|
||||
| Score Range | Severity |
|
||||
|-------------|----------|
|
||||
| 0.0 | None |
|
||||
| 0.1 - 3.9 | Low |
|
||||
| 4.0 - 6.9 | Medium |
|
||||
| 7.0 - 8.9 | High |
|
||||
| 9.0 - 10.0 | Critical |
|
||||
|
||||
### CVSS v4.0 Vector String Format
|
||||
```
|
||||
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
|
||||
```
|
||||
This example represents a network-exploitable vulnerability requiring no privileges, no user interaction, no attack requirements, with high impact on confidentiality, integrity, and availability of the vulnerable system.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: Assess Base Metrics
|
||||
For each vulnerability, evaluate:
|
||||
|
||||
```
|
||||
Example: CVE-2024-3094 (XZ Utils Backdoor)
|
||||
|
||||
Attack Vector: Network (N) - Exploitable over network
|
||||
Attack Complexity: High (H) - Specific conditions required
|
||||
Attack Requirements: Present (P) - Specific build/config needed
|
||||
Privileges Required: None (N) - No authentication needed
|
||||
User Interaction: None (N) - No victim action needed
|
||||
|
||||
Vulnerable System Impact:
|
||||
Confidentiality: High (H) - Complete access to SSH keys
|
||||
Integrity: High (H) - Arbitrary code execution
|
||||
Availability: High (H) - Full system compromise
|
||||
|
||||
Subsequent System Impact:
|
||||
Confidentiality: High (H) - Lateral movement possible
|
||||
Integrity: High (H) - Network-wide compromise
|
||||
Availability: None (N) - No downstream availability impact
|
||||
|
||||
Vector: CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:N
|
||||
```
|
||||
|
||||
### Step 2: Apply Threat Intelligence Context
|
||||
Enrich CVSS with real-world threat data:
|
||||
|
||||
```
|
||||
Exploit Maturity: Attacked (A) - Active exploitation in the wild
|
||||
EPSS Score: 0.94 - 94% probability of exploitation in 30 days
|
||||
CISA KEV: Listed - Mandatory remediation for federal agencies
|
||||
```
|
||||
|
||||
### Step 3: Calculate Environmental Score
|
||||
Adjust for organizational context:
|
||||
|
||||
```
|
||||
Confidentiality Req: High (H) - Handles PII/financial data
|
||||
Integrity Req: High (H) - Critical business process
|
||||
Availability Req: Medium (M) - Has DR/failover capability
|
||||
|
||||
Modified Attack Vector: Network (N) - Internet-facing deployment
|
||||
```
|
||||
|
||||
### Step 4: Multi-Factor Prioritization Matrix
|
||||
|
||||
Combine CVSS with additional prioritization factors:
|
||||
|
||||
| Factor | Weight | Source |
|
||||
|--------|--------|--------|
|
||||
| CVSS Base Score | 25% | NVD/Scanner |
|
||||
| EPSS Score | 25% | FIRST EPSS API |
|
||||
| Asset Criticality | 20% | Asset inventory/CMDB |
|
||||
| CISA KEV Listed | 15% | CISA catalog |
|
||||
| Network Exposure | 15% | Network segmentation data |
|
||||
|
||||
### Step 5: Define Remediation SLAs
|
||||
|
||||
| Priority Level | CVSS Range | EPSS | Asset Tier | SLA |
|
||||
|---------------|------------|------|------------|-----|
|
||||
| P1 - Emergency | 9.0-10.0 | >0.5 | Tier 1 | 24-48 hours |
|
||||
| P2 - Critical | 7.0-8.9 | >0.3 | Tier 1-2 | 7 days |
|
||||
| P3 - High | 7.0-8.9 | <0.3 | Tier 2-3 | 14 days |
|
||||
| P4 - Medium | 4.0-6.9 | Any | Any | 30 days |
|
||||
| P5 - Low | 0.1-3.9 | Any | Any | 90 days |
|
||||
|
||||
## Best Practices
|
||||
1. Never rely solely on CVSS base score for prioritization
|
||||
2. Always incorporate threat intelligence (EPSS, KEV, exploit databases)
|
||||
3. Maintain accurate asset criticality ratings in your CMDB
|
||||
4. Adjust environmental metrics for your specific deployment context
|
||||
5. Use CVSS v4.0 vector strings for precise communication between teams
|
||||
6. Document scoring rationale for audit trail and consistency
|
||||
7. Re-evaluate scores when new threat intelligence becomes available
|
||||
8. Train remediation teams on interpreting CVSS metrics and vector strings
|
||||
|
||||
## Common Pitfalls
|
||||
- Treating CVSS base score as the sole prioritization factor
|
||||
- Ignoring environmental metrics that reflect organizational risk
|
||||
- Not updating threat metrics when exploit maturity changes
|
||||
- Confusing CVSS severity with actual organizational risk
|
||||
- Using outdated CVSS v2.0 scores instead of v3.1/v4.0
|
||||
- Over-relying on scanner-provided scores without validation
|
||||
|
||||
## Related Skills
|
||||
- prioritizing-patches-with-exploit-prediction-scoring
|
||||
- implementing-risk-based-vulnerability-management
|
||||
- implementing-vulnerability-remediation-sla
|
||||
@@ -0,0 +1,36 @@
|
||||
# Vulnerability Prioritization Report Template
|
||||
|
||||
## Assessment Summary
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Report Date | [YYYY-MM-DD] |
|
||||
| Assessment Period | [START] to [END] |
|
||||
| Total CVEs Evaluated | [N] |
|
||||
| Scoring Framework | CVSS v4.0 + EPSS + CISA KEV |
|
||||
|
||||
## Priority Distribution
|
||||
| Priority | Count | % | SLA | Status |
|
||||
|----------|-------|---|-----|--------|
|
||||
| P1 - Emergency | [N] | [%] | 48 hours | [On Track/Overdue] |
|
||||
| P2 - Critical | [N] | [%] | 7 days | [On Track/Overdue] |
|
||||
| P3 - High | [N] | [%] | 14 days | [On Track/Overdue] |
|
||||
| P4 - Medium | [N] | [%] | 30 days | [On Track/Overdue] |
|
||||
| P5 - Low | [N] | [%] | 90 days | [On Track/Overdue] |
|
||||
|
||||
## Top 10 Prioritized Vulnerabilities
|
||||
| Rank | CVE | CVSS | EPSS | KEV | Asset | Priority | SLA |
|
||||
|------|-----|------|------|-----|-------|----------|-----|
|
||||
| 1 | [CVE-ID] | [N.N] | [0.NN] | [Y/N] | [Asset] | P1 | 48h |
|
||||
|
||||
## Scoring Methodology
|
||||
- **CVSS Base Score (25%)**: NVD v4.0/v3.1 base score
|
||||
- **EPSS Score (25%)**: FIRST Exploit Prediction Scoring System
|
||||
- **Asset Criticality (20%)**: CMDB tier rating (1-5)
|
||||
- **CISA KEV Status (15%)**: Known exploited vulnerability indicator
|
||||
- **Network Exposure (15%)**: Internet/DMZ/Internal exposure level
|
||||
|
||||
## Remediation Tracking
|
||||
| Priority | Open | In Progress | Remediated | Overdue |
|
||||
|----------|------|-------------|------------|---------|
|
||||
| P1 | [N] | [N] | [N] | [N] |
|
||||
| P2 | [N] | [N] | [N] | [N] |
|
||||
@@ -0,0 +1,38 @@
|
||||
# Standards and References - CVSS Scoring
|
||||
|
||||
## Official CVSS Documentation
|
||||
- CVSS v4.0 Specification: https://www.first.org/cvss/specification-document
|
||||
- CVSS v4.0 User Guide: https://www.first.org/cvss/v4.0/user-guide
|
||||
- CVSS v4.0 Calculator: https://www.first.org/cvss/calculator/4.0
|
||||
- NVD CVSS v4 Calculator: https://nvd.nist.gov/vuln-metrics/cvss/v4-calculator
|
||||
- Red Hat CVSS v4 Calculator: https://github.com/RedHatProductSecurity/cvss-v4-calculator
|
||||
|
||||
## Complementary Scoring Systems
|
||||
- EPSS (Exploit Prediction): https://www.first.org/epss/
|
||||
- SSVC (Stakeholder-Specific): https://www.cisa.gov/ssvc
|
||||
- CISA KEV Catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
|
||||
|
||||
## Industry Standards
|
||||
- **NIST SP 800-40 Rev 4**: Guide to Enterprise Patch Management Planning
|
||||
- **NIST NVD**: National Vulnerability Database uses CVSS for all CVEs
|
||||
- **PCI DSS v4.0**: Requires CVSS scoring for vulnerability prioritization
|
||||
- **ISO 27001:2022 A.8.8**: Technical vulnerability management
|
||||
|
||||
## CVSS v4.0 vs v3.1 Key Differences
|
||||
| Feature | CVSS v3.1 | CVSS v4.0 |
|
||||
|---------|-----------|-----------|
|
||||
| Metric Groups | 3 (Base, Temporal, Environmental) | 4 (Base, Threat, Environmental, Supplemental) |
|
||||
| Attack Requirements | N/A | New metric (AT) |
|
||||
| User Interaction | None/Required | None/Passive/Active |
|
||||
| Scope | Changed/Unchanged | Replaced by Subsequent System metrics |
|
||||
| Temporal -> Threat | Report Confidence, RL, E | Only Exploit Maturity |
|
||||
| Supplemental | N/A | Safety, Automatable, Recovery, etc. |
|
||||
|
||||
## Severity Thresholds
|
||||
| Rating | CVSS v3.1 | CVSS v4.0 |
|
||||
|--------|-----------|-----------|
|
||||
| None | 0.0 | 0.0 |
|
||||
| Low | 0.1 - 3.9 | 0.1 - 3.9 |
|
||||
| Medium | 4.0 - 6.9 | 4.0 - 6.9 |
|
||||
| High | 7.0 - 8.9 | 7.0 - 8.9 |
|
||||
| Critical | 9.0 - 10.0 | 9.0 - 10.0 |
|
||||
@@ -0,0 +1,53 @@
|
||||
# Workflows - CVSS Vulnerability Prioritization
|
||||
|
||||
## Workflow 1: Vulnerability Scoring Pipeline
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│ Receive CVE / │────>│ Look Up NVD │────>│ Extract CVSS │
|
||||
│ Scan Results │ │ Base Score │ │ Vector String │
|
||||
└──────────────────┘ └──────────────────┘ └──────────────────┘
|
||||
│
|
||||
┌────────────────────────────────────────────────┘
|
||||
v
|
||||
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│ Enrich with EPSS │────>│ Check CISA KEV │────>│ Apply Env Metrics│
|
||||
│ Threat Score │ │ Catalog │ │ (Asset Context) │
|
||||
└──────────────────┘ └──────────────────┘ └──────────────────┘
|
||||
│
|
||||
v
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Calculate Final │────>│ Assign Priority │
|
||||
│ Risk Score │ │ & SLA │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
## Workflow 2: Risk-Weighted Prioritization
|
||||
|
||||
```
|
||||
For each vulnerability:
|
||||
1. base_score = NVD CVSS v4.0 base score (0-10)
|
||||
2. epss_score = FIRST EPSS probability (0-1)
|
||||
3. asset_score = CMDB criticality rating (1-5)
|
||||
4. exposure_score = Network exposure (1=internal, 3=DMZ, 5=internet)
|
||||
5. kev_bonus = 2.0 if in CISA KEV, else 0
|
||||
|
||||
risk_score = (base_score * 0.25) +
|
||||
(epss_score * 10 * 0.25) +
|
||||
(asset_score * 2 * 0.20) +
|
||||
(exposure_score * 2 * 0.15) +
|
||||
kev_bonus * 0.15
|
||||
|
||||
priority = map_to_sla(risk_score)
|
||||
```
|
||||
|
||||
## Workflow 3: Continuous Re-Scoring
|
||||
|
||||
| Trigger | Action |
|
||||
|---------|--------|
|
||||
| New CVE published | Score with base metrics, schedule review |
|
||||
| EPSS update (daily) | Refresh EPSS scores, re-prioritize |
|
||||
| Exploit published | Update Exploit Maturity to POC or Attacked |
|
||||
| Added to CISA KEV | Elevate priority to P1/P2 |
|
||||
| Patch available | Add to remediation queue |
|
||||
| Asset decommissioned | Close associated findings |
|
||||
@@ -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