mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-19 14:09:40 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
---
|
||||
name: triaging-vulnerabilities-with-ssvc-framework
|
||||
description: Triage and prioritize vulnerabilities using CISA's Stakeholder-Specific Vulnerability Categorization (SSVC) decision tree framework to produce actionable remediation priorities.
|
||||
domain: cybersecurity
|
||||
subdomain: vulnerability-management
|
||||
tags: [ssvc, vulnerability-triage, cisa, vulnerability-prioritization, decision-tree, cvss, remediation, risk-management]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Triaging Vulnerabilities with SSVC Framework
|
||||
|
||||
## Overview
|
||||
|
||||
The Stakeholder-Specific Vulnerability Categorization (SSVC) framework, developed by Carnegie Mellon University's Software Engineering Institute (SEI) in collaboration with CISA, provides a structured decision-tree methodology for vulnerability prioritization. Unlike CVSS alone, SSVC accounts for exploitation status, technical impact, automatability, mission prevalence, and public well-being impact to produce one of four actionable outcomes: **Track**, **Track***, **Attend**, or **Act**.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.9+ with `requests`, `pandas`, and `jinja2` libraries
|
||||
- Access to CISA KEV catalog API and EPSS API from FIRST
|
||||
- NVD API key (optional, for higher rate limits)
|
||||
- Vulnerability scan results from tools like OpenVAS, Nessus, or Qualys
|
||||
|
||||
## SSVC Decision Points
|
||||
|
||||
### 1. Exploitation Status
|
||||
Assess current exploitation activity:
|
||||
- **None** - No evidence of active exploitation
|
||||
- **PoC** - Proof-of-concept exists publicly
|
||||
- **Active** - Active exploitation observed in the wild (check CISA KEV)
|
||||
|
||||
```bash
|
||||
# Check if a CVE is in CISA Known Exploited Vulnerabilities catalog
|
||||
curl -s "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json" | \
|
||||
python3 -c "import sys,json; data=json.load(sys.stdin); cves=[v['cveID'] for v in data['vulnerabilities']]; print('Active' if 'CVE-2024-3400' in cves else 'Check PoC/None')"
|
||||
```
|
||||
|
||||
### 2. Technical Impact
|
||||
Determine scope of compromise if exploited:
|
||||
- **Partial** - Limited to a subset of system functionality or data
|
||||
- **Total** - Full control of the affected system, complete data access
|
||||
|
||||
### 3. Automatability
|
||||
Evaluate if exploitation can be automated at scale:
|
||||
- **No** - Requires manual, targeted exploitation per victim
|
||||
- **Yes** - Can be scripted or worm-like propagation is possible
|
||||
|
||||
### 4. Mission Prevalence
|
||||
How widespread is the affected product in your environment:
|
||||
- **Minimal** - Limited deployment, non-critical systems
|
||||
- **Support** - Supports mission-critical functions indirectly
|
||||
- **Essential** - Directly enables core mission capabilities
|
||||
|
||||
### 5. Public Well-Being Impact
|
||||
Potential consequences for physical safety and public welfare:
|
||||
- **Minimal** - Negligible impact on safety or public services
|
||||
- **Material** - Noticeable degradation of public services
|
||||
- **Irreversible** - Loss of life, major property damage, or critical infrastructure failure
|
||||
|
||||
## SSVC Decision Outcomes
|
||||
|
||||
| Outcome | Action Required | SLA |
|
||||
|---------|----------------|-----|
|
||||
| **Track** | Monitor, remediate in normal patch cycle | 90 days |
|
||||
| **Track*** | Monitor closely, prioritize in next patch window | 60 days |
|
||||
| **Attend** | Escalate to senior management, accelerate remediation | 14 days |
|
||||
| **Act** | Apply mitigations immediately, executive-level awareness | 48 hours |
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: Ingest Vulnerability Data
|
||||
```python
|
||||
import requests
|
||||
import json
|
||||
|
||||
# Fetch CISA KEV catalog
|
||||
kev_url = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
||||
kev_data = requests.get(kev_url).json()
|
||||
kev_cves = {v['cveID'] for v in kev_data['vulnerabilities']}
|
||||
|
||||
# Fetch EPSS scores for context
|
||||
epss_url = "https://api.first.org/data/v1/epss"
|
||||
epss_response = requests.get(epss_url, params={"cve": "CVE-2024-3400"}).json()
|
||||
```
|
||||
|
||||
### Step 2: Evaluate Each Decision Point
|
||||
```python
|
||||
def evaluate_exploitation(cve_id, kev_set):
|
||||
"""Determine exploitation status from CISA KEV and EPSS data."""
|
||||
if cve_id in kev_set:
|
||||
return "active"
|
||||
epss = requests.get(
|
||||
"https://api.first.org/data/v1/epss",
|
||||
params={"cve": cve_id}
|
||||
).json()
|
||||
if epss.get("data"):
|
||||
score = float(epss["data"][0].get("epss", 0))
|
||||
if score > 0.5:
|
||||
return "poc"
|
||||
return "none"
|
||||
|
||||
def evaluate_technical_impact(cvss_vector):
|
||||
"""Parse CVSS vector for scope and impact metrics."""
|
||||
if "S:C" in cvss_vector or "C:H/I:H/A:H" in cvss_vector:
|
||||
return "total"
|
||||
return "partial"
|
||||
|
||||
def evaluate_automatability(cvss_vector, cve_description):
|
||||
"""Check if attack vector is network-based with low complexity."""
|
||||
if "AV:N" in cvss_vector and "AC:L" in cvss_vector and "UI:N" in cvss_vector:
|
||||
return "yes"
|
||||
return "no"
|
||||
```
|
||||
|
||||
### Step 3: Apply SSVC Decision Tree
|
||||
```python
|
||||
def ssvc_decision(exploitation, tech_impact, automatability, mission_prevalence, public_wellbeing):
|
||||
"""CISA SSVC decision tree implementation."""
|
||||
if exploitation == "active":
|
||||
if tech_impact == "total" or automatability == "yes":
|
||||
return "Act"
|
||||
if mission_prevalence in ("essential", "support"):
|
||||
return "Act"
|
||||
return "Attend"
|
||||
if exploitation == "poc":
|
||||
if automatability == "yes" and tech_impact == "total":
|
||||
return "Attend"
|
||||
if mission_prevalence == "essential":
|
||||
return "Attend"
|
||||
return "Track*"
|
||||
# exploitation == "none"
|
||||
if tech_impact == "total" and mission_prevalence == "essential":
|
||||
return "Track*"
|
||||
return "Track"
|
||||
```
|
||||
|
||||
### Step 4: Generate Triage Report
|
||||
```bash
|
||||
# Run the SSVC triage script against scan results
|
||||
python3 scripts/process.py --input scan_results.csv --output ssvc_triage_report.json
|
||||
|
||||
# View summary
|
||||
cat ssvc_triage_report.json | python3 -m json.tool | head -50
|
||||
```
|
||||
|
||||
## Integration with Vulnerability Scanners
|
||||
|
||||
### Import from Nessus CSV
|
||||
```bash
|
||||
# Export Nessus scan as CSV, then process
|
||||
python3 scripts/process.py \
|
||||
--input nessus_export.csv \
|
||||
--format nessus \
|
||||
--output ssvc_results.json
|
||||
```
|
||||
|
||||
### Import from OpenVAS
|
||||
```bash
|
||||
# Export OpenVAS results as XML
|
||||
python3 scripts/process.py \
|
||||
--input openvas_report.xml \
|
||||
--format openvas \
|
||||
--output ssvc_results.json
|
||||
```
|
||||
|
||||
## Validation and Testing
|
||||
|
||||
```bash
|
||||
# Test SSVC decision logic with known CVEs
|
||||
python3 -c "
|
||||
from scripts.process import ssvc_decision
|
||||
# CVE-2024-3400 - Palo Alto PAN-OS command injection (KEV listed)
|
||||
assert ssvc_decision('active', 'total', 'yes', 'essential', 'material') == 'Act'
|
||||
# CVE-2024-21887 - Ivanti Connect Secure (PoC available)
|
||||
assert ssvc_decision('poc', 'total', 'yes', 'support', 'minimal') == 'Attend'
|
||||
print('All SSVC decision tests passed')
|
||||
"
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [CISA SSVC Framework](https://www.cisa.gov/stakeholder-specific-vulnerability-categorization-ssvc)
|
||||
- [CERT/CC SSVC Documentation](https://certcc.github.io/SSVC/)
|
||||
- [CISA SSVC Guide PDF](https://www.cisa.gov/sites/default/files/publications/cisa-ssvc-guide%20508c.pdf)
|
||||
- [FIRST EPSS API](https://www.first.org/epss/)
|
||||
- [CISA Known Exploited Vulnerabilities](https://www.cisa.gov/known-exploited-vulnerabilities-catalog)
|
||||
@@ -0,0 +1,64 @@
|
||||
# Standards and References - SSVC Vulnerability Triage
|
||||
|
||||
## Primary Standards
|
||||
|
||||
### CISA SSVC Framework
|
||||
- **Source**: Cybersecurity and Infrastructure Security Agency (CISA)
|
||||
- **URL**: https://www.cisa.gov/stakeholder-specific-vulnerability-categorization-ssvc
|
||||
- **Version**: SSVC v2.0 (2022 revision by CISA with SEI)
|
||||
- **Purpose**: Provides a decision-tree methodology for vulnerability prioritization based on five decision points specific to the stakeholder's context
|
||||
|
||||
### CERT/CC SSVC Original Research
|
||||
- **Source**: Carnegie Mellon University Software Engineering Institute
|
||||
- **URL**: https://certcc.github.io/SSVC/
|
||||
- **Publication**: "Prioritizing Vulnerability Response: A Stakeholder-Specific Vulnerability Categorization" (2019)
|
||||
- **Authors**: Jonathan Spring, Eric Hatleback, Allen Householder, Art Manion, Deana Shick
|
||||
- **DOI**: https://doi.org/10.1184/R1/12124386
|
||||
|
||||
### CVSS v3.1 and v4.0
|
||||
- **Source**: Forum of Incident Response and Security Teams (FIRST)
|
||||
- **URL**: https://www.first.org/cvss/
|
||||
- **CVSS v3.1 Specification**: https://www.first.org/cvss/v3.1/specification-document
|
||||
- **CVSS v4.0 Specification**: https://www.first.org/cvss/v4.0/specification-document
|
||||
- **Relevance**: SSVC complements CVSS by adding contextual decision points beyond base score severity
|
||||
|
||||
### EPSS - Exploit Prediction Scoring System
|
||||
- **Source**: FIRST EPSS Special Interest Group
|
||||
- **URL**: https://www.first.org/epss/
|
||||
- **API Endpoint**: https://api.first.org/data/v1/epss
|
||||
- **Model Documentation**: https://www.first.org/epss/model
|
||||
- **Relevance**: EPSS probability scores inform the exploitation status decision point in SSVC
|
||||
|
||||
## Regulatory and Compliance Context
|
||||
|
||||
### CISA Binding Operational Directive 22-01
|
||||
- **Title**: Reducing the Significant Risk of Known Exploited Vulnerabilities
|
||||
- **URL**: https://www.cisa.gov/binding-operational-directive-22-01
|
||||
- **Relevance**: Mandates federal agencies to remediate KEV-listed vulnerabilities within specified timeframes; SSVC aligns remediation priorities with BOD 22-01 requirements
|
||||
|
||||
### NIST SP 800-40 Rev 4
|
||||
- **Title**: Guide to Enterprise Patch Management Planning
|
||||
- **URL**: https://csrc.nist.gov/publications/detail/sp/800-40/rev-4/final
|
||||
- **Relevance**: Provides organizational context for patch management decisions that SSVC informs
|
||||
|
||||
### NIST Cybersecurity Framework (CSF) 2.0
|
||||
- **Function**: IDENTIFY (ID.RA - Risk Assessment)
|
||||
- **URL**: https://www.nist.gov/cyberframework
|
||||
- **Relevance**: SSVC directly supports the risk assessment category for vulnerability prioritization
|
||||
|
||||
## Data Sources
|
||||
|
||||
### CISA Known Exploited Vulnerabilities (KEV) Catalog
|
||||
- **URL**: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
|
||||
- **JSON Feed**: https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json
|
||||
- **Update Frequency**: Updated as new exploited vulnerabilities are confirmed
|
||||
|
||||
### National Vulnerability Database (NVD)
|
||||
- **URL**: https://nvd.nist.gov/
|
||||
- **API v2**: https://services.nvd.nist.gov/rest/json/cves/2.0
|
||||
- **Relevance**: Provides CVSS scores and vulnerability details used in SSVC decision points
|
||||
|
||||
### MITRE CVE Program
|
||||
- **URL**: https://cve.mitre.org/
|
||||
- **CVE List**: https://www.cve.org/
|
||||
- **Relevance**: CVE identifiers are the primary key for linking vulnerability data across SSVC decision points
|
||||
@@ -0,0 +1,115 @@
|
||||
# Workflows - SSVC Vulnerability Triage
|
||||
|
||||
## Workflow 1: Initial SSVC Triage Pipeline
|
||||
|
||||
### Trigger
|
||||
New vulnerability scan results imported from Nessus, Qualys, OpenVAS, or other scanner.
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Ingest Scan Results**
|
||||
- Parse scanner output (CSV, XML, or JSON format)
|
||||
- Extract CVE identifiers, affected hosts, CVSS vectors, and descriptions
|
||||
- Deduplicate findings by CVE + host combination
|
||||
|
||||
2. **Enrich with External Intelligence**
|
||||
- Query CISA KEV catalog JSON feed for exploitation status
|
||||
- Query FIRST EPSS API for exploitation probability scores
|
||||
- Query NVD API v2 for CVSS v3.1/v4.0 vectors and CWE mappings
|
||||
- Cache API responses to avoid rate limiting (NVD: 5 requests/30s without key, 50/30s with key)
|
||||
|
||||
3. **Evaluate SSVC Decision Points**
|
||||
- **Exploitation**: Map KEV membership to "Active", EPSS > 0.5 to "PoC", otherwise "None"
|
||||
- **Technical Impact**: Parse CVSS vector; if Scope:Changed or CIA all High, mark "Total"
|
||||
- **Automatability**: Network vector + Low complexity + No user interaction = "Yes"
|
||||
- **Mission Prevalence**: Cross-reference affected assets with CMDB criticality tags
|
||||
- **Public Well-Being**: Map asset function to safety impact categories
|
||||
|
||||
4. **Apply Decision Tree**
|
||||
- Walk the CISA SSVC decision tree with evaluated decision points
|
||||
- Assign outcome: Track, Track*, Attend, or Act
|
||||
|
||||
5. **Generate Prioritized Report**
|
||||
- Sort vulnerabilities by SSVC outcome (Act > Attend > Track* > Track)
|
||||
- Within each category, secondary sort by EPSS score descending
|
||||
- Output JSON report and CSV summary for ticketing integration
|
||||
|
||||
## Workflow 2: Continuous SSVC Monitoring
|
||||
|
||||
### Trigger
|
||||
Daily scheduled job (cron or CI/CD pipeline).
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Refresh CISA KEV Catalog**
|
||||
```bash
|
||||
curl -s -o /tmp/kev_catalog.json \
|
||||
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
||||
```
|
||||
|
||||
2. **Check Previously Tracked CVEs Against Updated KEV**
|
||||
- Compare current open vulnerabilities against latest KEV additions
|
||||
- If a previously "Track" or "Track*" CVE appears in KEV, re-evaluate to "Attend" or "Act"
|
||||
|
||||
3. **Refresh EPSS Scores**
|
||||
```bash
|
||||
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3400,CVE-2024-21887" | \
|
||||
python3 -c "import sys,json; print(json.dumps(json.load(sys.stdin)['data'], indent=2))"
|
||||
```
|
||||
|
||||
4. **Update SSVC Outcomes**
|
||||
- Re-run decision tree for all open vulnerabilities with refreshed data
|
||||
- Flag any outcome changes (e.g., Track -> Attend)
|
||||
|
||||
5. **Send Notifications**
|
||||
- Slack/Teams webhook for any new "Act" or "Attend" outcomes
|
||||
- Email digest for "Track*" changes
|
||||
- Update Jira/ServiceNow tickets with new SSVC classification
|
||||
|
||||
## Workflow 3: Asset-Context SSVC Enrichment
|
||||
|
||||
### Trigger
|
||||
New asset onboarded or asset criticality classification updated.
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Import Asset Inventory**
|
||||
- Pull from CMDB (ServiceNow, Snipe-IT, or similar)
|
||||
- Map each asset to mission prevalence category:
|
||||
- Minimal: development, test environments
|
||||
- Support: backup systems, monitoring infrastructure
|
||||
- Essential: production databases, authentication servers, customer-facing apps
|
||||
|
||||
2. **Map Public Well-Being Impact**
|
||||
- Healthcare systems, SCADA/ICS, transportation: Irreversible
|
||||
- Public web services, financial processing: Material
|
||||
- Internal tools, development systems: Minimal
|
||||
|
||||
3. **Re-Evaluate Open Vulnerabilities**
|
||||
- Apply updated asset context to all open vulnerability SSVC evaluations
|
||||
- Generate delta report showing outcome changes
|
||||
|
||||
## Workflow 4: SSVC Metrics and Reporting
|
||||
|
||||
### Trigger
|
||||
Weekly/monthly reporting cycle.
|
||||
|
||||
### Metrics to Track
|
||||
|
||||
| Metric | Calculation | Target |
|
||||
|--------|------------|--------|
|
||||
| Mean Time to Remediate (Act) | Avg days from Act classification to closure | < 2 days |
|
||||
| Mean Time to Remediate (Attend) | Avg days from Attend classification to closure | < 14 days |
|
||||
| SLA Breach Rate | % of vulns not remediated within SLA | < 5% |
|
||||
| Act Backlog | Count of open Act-classified vulnerabilities | 0 |
|
||||
| Attend Backlog | Count of open Attend-classified vulnerabilities | < 10 |
|
||||
| Coverage Rate | % of vulnerabilities processed through SSVC | > 95% |
|
||||
|
||||
### Report Generation
|
||||
```bash
|
||||
python3 scripts/process.py \
|
||||
--mode report \
|
||||
--input ssvc_results.json \
|
||||
--period weekly \
|
||||
--output ssvc_metrics_report.html
|
||||
```
|
||||
@@ -0,0 +1,346 @@
|
||||
#!/usr/bin/env python3
|
||||
"""SSVC Vulnerability Triage Processor.
|
||||
|
||||
Evaluates vulnerabilities against CISA's Stakeholder-Specific Vulnerability
|
||||
Categorization (SSVC) decision tree and produces prioritized triage reports.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import xml.etree.ElementTree as ET
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
||||
EPSS_API = "https://api.first.org/data/v1/epss"
|
||||
NVD_API = "https://services.nvd.nist.gov/rest/json/cves/2.0"
|
||||
|
||||
SSVC_SLA = {
|
||||
"Act": 2,
|
||||
"Attend": 14,
|
||||
"Track*": 60,
|
||||
"Track": 90,
|
||||
}
|
||||
|
||||
|
||||
def fetch_kev_catalog():
|
||||
"""Download the CISA Known Exploited Vulnerabilities catalog."""
|
||||
resp = requests.get(KEV_URL, timeout=30)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
return {v["cveID"] for v in data.get("vulnerabilities", [])}
|
||||
|
||||
|
||||
def fetch_epss_scores(cve_ids):
|
||||
"""Fetch EPSS scores for a list of CVE IDs from FIRST API."""
|
||||
scores = {}
|
||||
batch_size = 100
|
||||
for i in range(0, len(cve_ids), batch_size):
|
||||
batch = cve_ids[i : i + batch_size]
|
||||
params = {"cve": ",".join(batch)}
|
||||
resp = requests.get(EPSS_API, params=params, timeout=30)
|
||||
if resp.status_code == 200:
|
||||
for entry in resp.json().get("data", []):
|
||||
scores[entry["cve"]] = {
|
||||
"epss": float(entry.get("epss", 0)),
|
||||
"percentile": float(entry.get("percentile", 0)),
|
||||
}
|
||||
time.sleep(1)
|
||||
return scores
|
||||
|
||||
|
||||
def fetch_nvd_cve(cve_id, api_key=None):
|
||||
"""Fetch CVE details from NVD API v2."""
|
||||
params = {"cveId": cve_id}
|
||||
headers = {}
|
||||
if api_key:
|
||||
headers["apiKey"] = api_key
|
||||
resp = requests.get(NVD_API, params=params, headers=headers, timeout=30)
|
||||
if resp.status_code == 200:
|
||||
vulns = resp.json().get("vulnerabilities", [])
|
||||
if vulns:
|
||||
return vulns[0].get("cve", {})
|
||||
return None
|
||||
|
||||
|
||||
def evaluate_exploitation(cve_id, kev_set, epss_scores):
|
||||
"""Determine exploitation status: active, poc, or none."""
|
||||
if cve_id in kev_set:
|
||||
return "active"
|
||||
epss_data = epss_scores.get(cve_id, {})
|
||||
if epss_data.get("epss", 0) > 0.5:
|
||||
return "poc"
|
||||
if epss_data.get("epss", 0) > 0.1:
|
||||
return "poc"
|
||||
return "none"
|
||||
|
||||
|
||||
def evaluate_technical_impact(cvss_vector):
|
||||
"""Assess technical impact from CVSS vector string."""
|
||||
if not cvss_vector:
|
||||
return "partial"
|
||||
vector_upper = cvss_vector.upper()
|
||||
if "S:C" in vector_upper:
|
||||
return "total"
|
||||
if "C:H" in vector_upper and "I:H" in vector_upper and "A:H" in vector_upper:
|
||||
return "total"
|
||||
if "C:H" in vector_upper and "I:H" in vector_upper:
|
||||
return "total"
|
||||
return "partial"
|
||||
|
||||
|
||||
def evaluate_automatability(cvss_vector):
|
||||
"""Determine if exploitation can be automated."""
|
||||
if not cvss_vector:
|
||||
return "no"
|
||||
vector_upper = cvss_vector.upper()
|
||||
network = "AV:N" in vector_upper
|
||||
low_complexity = "AC:L" in vector_upper
|
||||
no_user_interaction = "UI:N" in vector_upper
|
||||
if network and low_complexity and no_user_interaction:
|
||||
return "yes"
|
||||
return "no"
|
||||
|
||||
|
||||
def ssvc_decision(exploitation, tech_impact, automatability, mission_prevalence, public_wellbeing):
|
||||
"""Apply CISA SSVC decision tree to produce triage outcome.
|
||||
|
||||
Returns one of: Act, Attend, Track*, Track
|
||||
"""
|
||||
if exploitation == "active":
|
||||
if automatability == "yes":
|
||||
return "Act"
|
||||
if tech_impact == "total":
|
||||
if mission_prevalence in ("essential", "support"):
|
||||
return "Act"
|
||||
return "Attend"
|
||||
if mission_prevalence == "essential":
|
||||
return "Attend"
|
||||
if public_wellbeing in ("irreversible", "material"):
|
||||
return "Attend"
|
||||
return "Attend"
|
||||
|
||||
if exploitation == "poc":
|
||||
if automatability == "yes" and tech_impact == "total":
|
||||
if mission_prevalence in ("essential", "support"):
|
||||
return "Attend"
|
||||
return "Track*"
|
||||
if tech_impact == "total" and mission_prevalence == "essential":
|
||||
return "Attend"
|
||||
if public_wellbeing == "irreversible":
|
||||
return "Attend"
|
||||
return "Track*"
|
||||
|
||||
# exploitation == "none"
|
||||
if tech_impact == "total" and mission_prevalence == "essential":
|
||||
return "Track*"
|
||||
if automatability == "yes" and mission_prevalence == "essential":
|
||||
return "Track*"
|
||||
return "Track"
|
||||
|
||||
|
||||
def parse_nessus_csv(filepath):
|
||||
"""Parse Nessus CSV export into vulnerability records."""
|
||||
vulns = []
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
cve = row.get("CVE", "").strip()
|
||||
if not cve or not cve.startswith("CVE-"):
|
||||
continue
|
||||
vulns.append(
|
||||
{
|
||||
"cve_id": cve,
|
||||
"host": row.get("Host", "unknown"),
|
||||
"port": row.get("Port", ""),
|
||||
"plugin_name": row.get("Name", ""),
|
||||
"severity": row.get("Severity", ""),
|
||||
"cvss_vector": row.get("CVSS V3 Vector", ""),
|
||||
"description": row.get("Synopsis", ""),
|
||||
}
|
||||
)
|
||||
return vulns
|
||||
|
||||
|
||||
def parse_openvas_xml(filepath):
|
||||
"""Parse OpenVAS XML report into vulnerability records."""
|
||||
vulns = []
|
||||
tree = ET.parse(filepath)
|
||||
root = tree.getroot()
|
||||
for result in root.iter("result"):
|
||||
nvt = result.find("nvt")
|
||||
if nvt is None:
|
||||
continue
|
||||
cve_elem = nvt.find("cve")
|
||||
if cve_elem is None or not cve_elem.text or cve_elem.text == "NOCVE":
|
||||
continue
|
||||
host_elem = result.find("host")
|
||||
port_elem = result.find("port")
|
||||
vulns.append(
|
||||
{
|
||||
"cve_id": cve_elem.text.strip(),
|
||||
"host": host_elem.text.strip() if host_elem is not None else "unknown",
|
||||
"port": port_elem.text.strip() if port_elem is not None else "",
|
||||
"plugin_name": nvt.findtext("name", ""),
|
||||
"severity": result.findtext("severity", ""),
|
||||
"cvss_vector": nvt.findtext("tags", ""),
|
||||
"description": result.findtext("description", ""),
|
||||
}
|
||||
)
|
||||
return vulns
|
||||
|
||||
|
||||
def parse_generic_csv(filepath):
|
||||
"""Parse generic CSV with cve_id, host, cvss_vector columns."""
|
||||
vulns = []
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
cve = row.get("cve_id", "").strip()
|
||||
if not cve:
|
||||
continue
|
||||
vulns.append(
|
||||
{
|
||||
"cve_id": cve,
|
||||
"host": row.get("host", "unknown"),
|
||||
"port": row.get("port", ""),
|
||||
"plugin_name": row.get("plugin_name", ""),
|
||||
"severity": row.get("severity", ""),
|
||||
"cvss_vector": row.get("cvss_vector", ""),
|
||||
"description": row.get("description", ""),
|
||||
"mission_prevalence": row.get("mission_prevalence", "support"),
|
||||
"public_wellbeing": row.get("public_wellbeing", "minimal"),
|
||||
}
|
||||
)
|
||||
return vulns
|
||||
|
||||
|
||||
def run_triage(vulns, kev_set, epss_scores, default_mission="support", default_wellbeing="minimal"):
|
||||
"""Run SSVC triage on a list of vulnerability records."""
|
||||
results = []
|
||||
for vuln in vulns:
|
||||
cve_id = vuln["cve_id"]
|
||||
exploitation = evaluate_exploitation(cve_id, kev_set, epss_scores)
|
||||
tech_impact = evaluate_technical_impact(vuln.get("cvss_vector", ""))
|
||||
automatability = evaluate_automatability(vuln.get("cvss_vector", ""))
|
||||
mission = vuln.get("mission_prevalence", default_mission)
|
||||
wellbeing = vuln.get("public_wellbeing", default_wellbeing)
|
||||
|
||||
outcome = ssvc_decision(exploitation, tech_impact, automatability, mission, wellbeing)
|
||||
epss_data = epss_scores.get(cve_id, {})
|
||||
|
||||
results.append(
|
||||
{
|
||||
"cve_id": cve_id,
|
||||
"host": vuln.get("host", "unknown"),
|
||||
"port": vuln.get("port", ""),
|
||||
"plugin_name": vuln.get("plugin_name", ""),
|
||||
"ssvc_outcome": outcome,
|
||||
"sla_days": SSVC_SLA[outcome],
|
||||
"exploitation_status": exploitation,
|
||||
"technical_impact": tech_impact,
|
||||
"automatability": automatability,
|
||||
"mission_prevalence": mission,
|
||||
"public_wellbeing": wellbeing,
|
||||
"epss_score": epss_data.get("epss", 0),
|
||||
"epss_percentile": epss_data.get("percentile", 0),
|
||||
"in_kev": cve_id in kev_set,
|
||||
}
|
||||
)
|
||||
|
||||
outcome_order = {"Act": 0, "Attend": 1, "Track*": 2, "Track": 3}
|
||||
results.sort(key=lambda r: (outcome_order.get(r["ssvc_outcome"], 4), -r["epss_score"]))
|
||||
return results
|
||||
|
||||
|
||||
def generate_report(results, output_path, report_format="json"):
|
||||
"""Generate triage report in JSON or CSV format."""
|
||||
summary = {
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"total_vulnerabilities": len(results),
|
||||
"outcome_counts": {},
|
||||
"results": results,
|
||||
}
|
||||
for r in results:
|
||||
outcome = r["ssvc_outcome"]
|
||||
summary["outcome_counts"][outcome] = summary["outcome_counts"].get(outcome, 0) + 1
|
||||
|
||||
if report_format == "csv":
|
||||
if results:
|
||||
with open(output_path, "w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=results[0].keys())
|
||||
writer.writeheader()
|
||||
writer.writerows(results)
|
||||
else:
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(summary, f, indent=2)
|
||||
|
||||
return summary
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="SSVC Vulnerability Triage Processor")
|
||||
parser.add_argument("--input", required=True, help="Path to vulnerability scan results")
|
||||
parser.add_argument("--output", default="ssvc_triage_report.json", help="Output report path")
|
||||
parser.add_argument(
|
||||
"--format",
|
||||
choices=["nessus", "openvas", "generic"],
|
||||
default="generic",
|
||||
help="Input format",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-format", choices=["json", "csv"], default="json", help="Output format"
|
||||
)
|
||||
parser.add_argument("--nvd-api-key", help="NVD API key for higher rate limits")
|
||||
parser.add_argument(
|
||||
"--mission-prevalence",
|
||||
choices=["minimal", "support", "essential"],
|
||||
default="support",
|
||||
help="Default mission prevalence",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--public-wellbeing",
|
||||
choices=["minimal", "material", "irreversible"],
|
||||
default="minimal",
|
||||
help="Default public well-being impact",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
print("[*] Fetching CISA KEV catalog...")
|
||||
kev_set = fetch_kev_catalog()
|
||||
print(f" Loaded {len(kev_set)} known exploited vulnerabilities")
|
||||
|
||||
print(f"[*] Parsing input file: {args.input}")
|
||||
if args.format == "nessus":
|
||||
vulns = parse_nessus_csv(args.input)
|
||||
elif args.format == "openvas":
|
||||
vulns = parse_openvas_xml(args.input)
|
||||
else:
|
||||
vulns = parse_generic_csv(args.input)
|
||||
print(f" Found {len(vulns)} vulnerability records")
|
||||
|
||||
cve_ids = list({v["cve_id"] for v in vulns})
|
||||
print(f"[*] Fetching EPSS scores for {len(cve_ids)} unique CVEs...")
|
||||
epss_scores = fetch_epss_scores(cve_ids)
|
||||
|
||||
print("[*] Running SSVC triage...")
|
||||
results = run_triage(
|
||||
vulns, kev_set, epss_scores, args.mission_prevalence, args.public_wellbeing
|
||||
)
|
||||
|
||||
print(f"[*] Generating report: {args.output}")
|
||||
summary = generate_report(results, args.output, args.output_format)
|
||||
|
||||
print("\n[+] SSVC Triage Summary:")
|
||||
for outcome, count in sorted(summary["outcome_counts"].items()):
|
||||
print(f" {outcome}: {count}")
|
||||
print(f" Total: {summary['total_vulnerabilities']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user