feat(cra): hardware path — derive cyber findings from networked components
For hardware CE projects (no repo) each networked component (controller/hmi/ gateway/drive/remote_access/sensor) yields typical ICS vulnerability CLASSES (real CWE + "CISA-ICS — product-specific check" framing, NO fabricated CVEs); they flow through the same CRA engine. /assess accepts components[]. MappedFinding now echoes title/location/cwe so the response is self-contained for any finding source. Live CISA-ICS/NVD per-product CVE lookup is the later enrichment. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""Derive cyber findings from a machine's networked components (hardware path).
|
||||
|
||||
For a hardware CE project there is no source repo to scan. Instead, each
|
||||
*networked* component (PLC, HMI, gateway, drive, remote access) carries typical
|
||||
ICS vulnerability CLASSES — well-established categories repeatedly flagged in
|
||||
CISA ICS advisories. We emit one finding per class so they flow through the same
|
||||
CRA engine.
|
||||
|
||||
Honesty: these are vulnerability CLASSES (with a real CWE), framed as
|
||||
"product-specific check against CISA ICS advisories" — NOT fabricated CVE numbers.
|
||||
The concrete CVEs per vendor/product are a later live CISA-ICS / NVD enrichment.
|
||||
"""
|
||||
|
||||
# component_class -> typical ICS vulnerability classes (suffix, title, cwe, severity, category)
|
||||
_CLASS_VULN_TEMPLATES = {
|
||||
"controller": [ # PLC / safety controller / motion controller
|
||||
("ctrl-noauth", "Steuerungsprotokoll ohne Authentifizierung erreichbar", "CWE-306", "high", "auth"),
|
||||
("ctrl-fw", "Firmware-/Programm-Update ohne Signaturpruefung", "CWE-494", "high", "updates"),
|
||||
("ctrl-debug", "Offener Programmier-/Debug-Port", "CWE-1188", "medium", "config"),
|
||||
],
|
||||
"hmi": [ # operator panel / SCADA HMI
|
||||
("hmi-default", "Default-/Werks-Zugangsdaten", "CWE-1392", "critical", "auth"),
|
||||
("hmi-cleartext", "Unverschluesselte Web-/Bedienoberflaeche", "CWE-319", "high", "crypto"),
|
||||
],
|
||||
"gateway": [ # IoT / fieldbus / telemetry gateway
|
||||
("gw-telemetry", "Unverschluesselte Telemetrie / Feldbus", "CWE-319", "high", "crypto"),
|
||||
("gw-bruteforce", "Kein Brute-Force-/Rate-Limit-Schutz am Zugang", "CWE-307", "medium", "auth"),
|
||||
],
|
||||
"drive": [ # VFD / servo drive
|
||||
("drv-param", "Antriebsparameter ueber unauthentifizierten Kanal aenderbar", "CWE-306", "high", "auth"),
|
||||
],
|
||||
"remote_access": [ # remote maintenance / VPN box
|
||||
("ra-default", "Fernzugang mit Default-Passwort", "CWE-259", "critical", "auth"),
|
||||
("ra-nomfa", "Keine starke Authentifizierung (MFA) fuer Fernzugang", "CWE-287", "high", "auth"),
|
||||
],
|
||||
"sensor": [ # networked sensor
|
||||
("sns-integrity", "Messwerte ohne Integritaetsschutz uebertragen", "CWE-345", "medium", "integrity"),
|
||||
],
|
||||
}
|
||||
|
||||
_SOURCE = "Komponenten-Klasse (CISA-ICS-typisch — produktspezifisch pruefen)"
|
||||
|
||||
|
||||
def findings_from_components(components: list) -> list:
|
||||
"""components: [{name, component_class, networked, vendor?, product?}]. Returns
|
||||
finding dicts (ScannerFinding-shaped) for the NETWORKED components only."""
|
||||
out = []
|
||||
for comp in components or []:
|
||||
if not comp.get("networked"):
|
||||
continue
|
||||
klass = (comp.get("component_class") or "").lower()
|
||||
name = comp.get("name") or klass or "Komponente"
|
||||
for suffix, title, cwe, severity, category in _CLASS_VULN_TEMPLATES.get(klass, []):
|
||||
out.append({
|
||||
"id": "{}-{}".format(name, suffix).replace(" ", "_"),
|
||||
"title": "{} ({})".format(title, name),
|
||||
"cwe": cwe,
|
||||
"severity": severity,
|
||||
"category": category,
|
||||
"location": name,
|
||||
"source": _SOURCE,
|
||||
})
|
||||
return out
|
||||
Reference in New Issue
Block a user