#!/usr/bin/env python3
"""Scope CVE-2008-4128 exposure from inventories and exported Cisco IOS telemetry.
Input: a directory containing CSV, JSON, JSONL, TXT, LOG, YAML, XML, config, or
AAA accounting exports. The script never contacts the network and does not run
untrusted code. It searches for the exact CVE, affected product/version selectors,
and the management-plane URI/command strings named by CISA/NVD.
Exit codes:
0: no matches
2: one or more selectors matched and review is required
3: execution error
"""
from __future__ import annotations
import json, os, sys
from pathlib import Path
CVE_ID = "CVE-2008-4128"
VENDOR = "Cisco"
PRODUCT = "IOS"
AFFECTED_VERSION_SELECTORS = [
"Cisco IOS 12.4",
"IOS 12.4",
"Cisco 871 Integrated Services Router",
"871 Integrated Services Router",
"cisco-ios 12.4 affected; fixed unknown_after_direct_source_review; 12.4 mainline obsolete",
]
SOURCE_SELECTORS = [
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
"https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2008-4128",
"https://nvd.nist.gov/vuln/detail/CVE-2008-4128",
"https://www.cisco.com/c/en/us/obsolete/ios-nx-os-software/cisco-ios-software-releases-12-4-mainline.html",
]
DOMAINS: list[str] = []
HASHES: list[str] = []
URLS: list[str] = []
FILES: list[str] = []
PROCESS_PATTERNS = [
"/level/15/exec/-",
"/level/15/exec/-/configure/http",
"show privilege",
"alias exec",
]
NETWORK_PATTERNS = [
"/level/15/exec/-",
"/level/15/exec/-/configure/http",
]
INDICATORS = [CVE_ID, *AFFECTED_VERSION_SELECTORS, *SOURCE_SELECTORS, *PROCESS_PATTERNS, *NETWORK_PATTERNS]
OUT = os.environ.get("OUT", "hp-cisco-ios-cve-2008-4128-kev-scope")
TEXT_SUFFIXES = {".csv", ".json", ".jsonl", ".txt", ".log", ".yaml", ".yml", ".xml", ".conf", ".ini", ".cfg", ".md"}
EXCLUDED_DIR_NAMES = {".git", "node_modules", "vendor", "dist", "__pycache__", ".venv"}
def read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8", errors="ignore")
except Exception:
return ""
def iter_files(root: Path):
if root.is_file():
yield root; return
for q in root.rglob("*"):
if q.is_file() and not any(part in EXCLUDED_DIR_NAMES for part in q.parts):
if not q.suffix or q.suffix.lower() in TEXT_SUFFIXES:
yield q
def scan(root: Path):
matches=[]; lowered=[s.lower() for s in INDICATORS if s]
for path in iter_files(root):
low=read_text(path).lower()
hits=sorted({INDICATORS[i] for i,s in enumerate(lowered) if s in low})
if hits:
matches.append({"path": str(path), "hits": hits})
return matches
def main(argv=None):
argv=argv or sys.argv[1:]
root=Path(argv[0]) if argv else Path(".")
try:
matches=scan(root)
out_dir=Path(OUT); out_dir.mkdir(parents=True, exist_ok=True)
report={"cve": CVE_ID, "vendor": VENDOR, "product": PRODUCT, "affected_version_selectors": AFFECTED_VERSION_SELECTORS, "source_selectors": SOURCE_SELECTORS, "match_count": len(matches), "matches": matches}
(out_dir/"scope_report.json").write_text(json.dumps(report, indent=2), encoding="utf-8")
print(json.dumps({"cve": CVE_ID, "match_count": len(matches), "report": str(out_dir/"scope_report.json")}, indent=2))
return 2 if matches else 0
except Exception as exc:
print(json.dumps({"cve": CVE_ID, "error": str(exc)}), file=sys.stderr)
return 3
if __name__ == "__main__":
raise SystemExit(main())