npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- When a registered entity must achieve or maintain NERC CIP compliance for BES cyber systems
- When preparing for a NERC CIP compliance audit by the Regional Entity
- When implementing the 2025 CIP standard updates (CIP-003-9, CIP-005-7, CIP-010-4, CIP-013-2)
- When categorizing BES cyber systems after commissioning new generation, transmission, or control center assets
- When developing a compliance monitoring and evidence collection program
Do not use for non-BES industrial systems (see implementing-iec-62443-security-zones), for general IT compliance frameworks (see auditing-cloud-with-cis-benchmarks), or for physical security of substations without cyber components.
Prerequisites
- Understanding of NERC CIP standards (CIP-002 through CIP-014)
- BES cyber system inventory with impact ratings (high, medium, low)
- Access to Electronic Security Perimeter (ESP) network diagrams and firewall configurations
- Compliance management system for evidence collection and audit documentation
- Familiarity with NERC Glossary of Terms (BES Cyber Asset, BES Cyber System, Electronic Access Point)
Workflow
Step 1: Categorize BES Cyber Systems (CIP-002-5.1a)
Identify and categorize all BES cyber systems based on their impact to the reliable operation of the Bulk Electric System.
#!/usr/bin/env python3
"""NERC CIP BES Cyber System Categorization Tool.
Implements CIP-002-5.1a categorization criteria to classify
BES cyber systems as high, medium, or low impact.
"""
import json
import sys
from dataclasses import dataclass, field, asdict
from datetime import datetime
@dataclass
class BESCyberSystem:
"""Represents a BES Cyber System for CIP-002 categorization."""
system_id: str
name: str
description: str
location: str
asset_type: str # control_center, generation, transmission, distribution
connected_mw: float = 0
transmission_kv: float = 0
is_control_center: bool = False
is_backup_control_center: bool = False
has_cranking_path: bool = False
has_blackstart: bool = False
is_sps_ras: bool = False # Special Protection System / Remedial Action Scheme
impact_rating: str = "" # high, medium, low
categorization_basis: str = ""
cyber_assets: list = field(default_factory=list)
class CIP002Categorizer:
"""NERC CIP-002-5.1a BES Cyber System categorization engine."""
def __init__(self):
self.systems = []
self.categorization_date = datetime.now().isoformat()
def add_system(self, system: BESCyberSystem):
self.systems.append(system)
def categorize_all(self):
"""Apply CIP-002 Attachment 1 criteria to all systems."""
for system in self.systems:
self._categorize_system(system)
def _categorize_system(self, sys):
"""Apply high, medium, low impact criteria per CIP-002 Attachment 1."""
# HIGH IMPACT criteria (CIP-002 Attachment 1, Criterion 1)
if sys.is_control_center and sys.asset_type == "control_center":
# Control Centers that perform the functional obligations
# of a Reliability Coordinator, Balancing Authority, or TOP
sys.impact_rating = "high"
sys.categorization_basis = (
"CIP-002 Att.1 Criterion 1.1: Control Center performing "
"RC/BA/TOP functional obligations"
)
return
if sys.is_backup_control_center and sys.asset_type == "control_center":
sys.impact_rating = "high"
sys.categorization_basis = (
"CIP-002 Att.1 Criterion 1.2: Backup Control Center performing "
"RC/BA/TOP functional obligations"
)
return
if sys.connected_mw >= 3000:
sys.impact_rating = "high"
sys.categorization_basis = (
f"CIP-002 Att.1 Criterion 1.3: Generation >= 3000 MW "
f"(actual: {sys.connected_mw} MW)"
)
return
# MEDIUM IMPACT criteria (CIP-002 Attachment 1, Criterion 2)
if sys.connected_mw >= 1500 and sys.asset_type == "generation":
sys.impact_rating = "medium"
sys.categorization_basis = (
f"CIP-002 Att.1 Criterion 2.1: Generation >= 1500 MW "
f"(actual: {sys.connected_mw} MW)"
)
return
if sys.transmission_kv >= 500:
sys.impact_rating = "medium"
sys.categorization_basis = (
f"CIP-002 Att.1 Criterion 2.5: Transmission >= 500 kV "
f"(actual: {sys.transmission_kv} kV)"
)
return
if sys.has_cranking_path:
sys.impact_rating = "medium"
sys.categorization_basis = (
"CIP-002 Att.1 Criterion 2.6: Cranking path element"
)
return
if sys.has_blackstart:
sys.impact_rating = "medium"
sys.categorization_basis = (
"CIP-002 Att.1 Criterion 2.7: Blackstart resource"
)
return
if sys.is_sps_ras:
sys.impact_rating = "medium"
sys.categorization_basis = (
"CIP-002 Att.1 Criterion 2.9: SPS/RAS component"
)
return
if sys.is_control_center and sys.asset_type == "generation":
sys.impact_rating = "medium"
sys.categorization_basis = (
"CIP-002 Att.1 Criterion 2.11: Generation control center "
"for medium impact generation"
)
return
# LOW IMPACT - all other BES Cyber Systems
sys.impact_rating = "low"
sys.categorization_basis = (
"CIP-002 Att.1 Criterion 3: BES Cyber System not meeting "
"high or medium impact criteria"
)
def generate_report(self):
"""Generate CIP-002 categorization report."""
high = [s for s in self.systems if s.impact_rating == "high"]
medium = [s for s in self.systems if s.impact_rating == "medium"]
low = [s for s in self.systems if s.impact_rating == "low"]
report = []
report.append("=" * 70)
report.append("NERC CIP-002-5.1a BES CYBER SYSTEM CATEGORIZATION")
report.append(f"Date: {self.categorization_date}")
report.append("=" * 70)
report.append(f"\nTotal BES Cyber Systems: {len(self.systems)}")
report.append(f" High Impact: {len(high)}")
report.append(f" Medium Impact: {len(medium)}")
report.append(f" Low Impact: {len(low)}")
for category, systems in [("HIGH", high), ("MEDIUM", medium), ("LOW", low)]:
if systems:
report.append(f"\n--- {category} IMPACT SYSTEMS ---")
for s in systems:
report.append(f" [{s.system_id}] {s.name}")
report.append(f" Location: {s.location}")
report.append(f" Type: {s.asset_type}")
report.append(f" Basis: {s.categorization_basis}")
report.append(f" Cyber Assets: {len(s.cyber_assets)}")
return "\n".join(report)
def export_json(self, output_file):
"""Export categorization to JSON for compliance evidence."""
data = {
"categorization_date": self.categorization_date,
"standard": "CIP-002-5.1a",
"systems": [asdict(s) for s in self.systems],
}
with open(output_file, "w") as f:
json.dump(data, f, indent=2)
if __name__ == "__main__":
categorizer = CIP002Categorizer()
# Example BES Cyber Systems
categorizer.add_system(BESCyberSystem(
system_id="BCS-001", name="Main Energy Control Center EMS",
description="Energy Management System for BA operations",
location="Control Center Alpha", asset_type="control_center",
is_control_center=True))
categorizer.add_system(BESCyberSystem(
system_id="BCS-002", name="Wind Farm SCADA",
description="SCADA for 500MW wind generation facility",
location="Wind Farm Delta", asset_type="generation",
connected_mw=500))
categorizer.add_system(BESCyberSystem(
system_id="BCS-003", name="Substation Alpha RTU",
description="345kV transmission substation",
location="Substation Alpha", asset_type="transmission",
transmission_kv=345))
categorizer.categorize_all()
print(categorizer.generate_report())Step 2: Implement Electronic Security Perimeters (CIP-005-7)
Define and enforce Electronic Security Perimeters (ESP) around high and medium impact BES cyber systems with Electronic Access Points (EAP) at all boundary crossing points.
# Electronic Security Perimeter - Firewall Configuration
# CIP-005-7 R1: Electronic Security Perimeter
# Define ESP boundary for Control Center EMS (High Impact)
# All BES Cyber Assets within the ESP boundary
# Palo Alto PA-3260 - ESP Boundary Firewall
# Inbound rules - strictly limit what enters the ESP
# CIP-005-7 R1.3: All inbound/outbound access permissions documented
# Allow ICCP (Inter-Control Center Communications Protocol) from neighbor BA
set rulebase security rules ICCP-Inbound from Corporate-Zone to ESP-Zone
set rulebase security rules ICCP-Inbound source 192.168.100.10
set rulebase security rules ICCP-Inbound destination 10.20.1.50
set rulebase security rules ICCP-Inbound application iccp
set rulebase security rules ICCP-Inbound service application-default
set rulebase security rules ICCP-Inbound action allow
set rulebase security rules ICCP-Inbound log-setting CIP-Audit-Log
# Allow NTP for time synchronization (CIP-007 R5.7)
set rulebase security rules NTP-Inbound from Corporate-Zone to ESP-Zone
set rulebase security rules NTP-Inbound source 192.168.100.1
set rulebase security rules NTP-Inbound destination 10.20.1.1
set rulebase security rules NTP-Inbound application ntp
set rulebase security rules NTP-Inbound action allow
# CIP-005-7 R2: Remote Access Management
# Require Intermediate System for all remote access sessions
# CIP-005-7 R2.4: Multi-factor authentication required (2025 update)
set rulebase security rules RemoteAccess from External to DMZ-Zone
set rulebase security rules RemoteAccess destination 172.16.1.10
set rulebase security rules RemoteAccess application ssl-vpn
set rulebase security rules RemoteAccess action allow
# MFA enforced on Intermediate System (jump server)
# Default deny all other traffic
set rulebase security rules ESP-Default-Deny from any to ESP-Zone
set rulebase security rules ESP-Default-Deny action deny
set rulebase security rules ESP-Default-Deny log-setting CIP-Audit-LogStep 3: Implement System Security Management (CIP-007-6)
Configure security controls for BES cyber assets including port management, security patching, malicious code prevention, and security event monitoring.
# CIP-007-6 Implementation Checklist
cip_007_controls:
R1_ports_services:
description: "Ports and Services Management"
requirements:
- "Disable or restrict all unnecessary physical ports (USB, serial)"
- "Disable all unnecessary logical ports and services"
- "Document all enabled ports/services with business justification"
implementation:
windows_servers: |
# Disable unnecessary services on Windows BES Cyber Assets
Set-Service -Name "RemoteRegistry" -StartupType Disabled
Set-Service -Name "WinRM" -StartupType Disabled
Set-Service -Name "Spooler" -StartupType Disabled
# Disable USB storage via Group Policy
# Computer Config > Admin Templates > System > Removable Storage Access
linux_servers: |
# Disable unnecessary services
systemctl disable cups bluetooth avahi-daemon
systemctl mask cups bluetooth avahi-daemon
# Disable USB storage
echo "blacklist usb-storage" > /etc/modprobe.d/disable-usb.conf
R2_security_patches:
description: "Security Patch Management"
requirements:
- "Track security patches for all BES Cyber Systems"
- "Evaluate patches within 35 days of availability"
- "Apply patches or document mitigation plan"
- "Test patches in non-production before deployment"
implementation:
tracking: "Use WSUS/SCCM for Windows; yum/dnf for Linux"
testing: "Maintain staging environment mirroring production"
evidence: "Document patch evaluation in compliance tracking system"
R3_malicious_code:
description: "Malicious Code Prevention"
requirements:
- "Deploy anti-malware on all applicable BES Cyber Assets"
- "Update signatures or use application allowlisting"
- "Mitigate threats from transient cyber assets"
implementation:
servers: "CrowdFalcon or Carbon Black with OT-optimized policy"
hmi_stations: "Application allowlisting (Carbon Black App Control)"
transient_devices: "Scan all removable media before connection to BCA"
R4_security_event_monitoring:
description: "Security Event Monitoring"
requirements:
- "Log security events on all high/medium impact BCS"
- "Generate alerts for detected security events"
- "Retain logs for minimum 90 days (CIP-007-6 R4.3)"
- "Review logs at minimum every 15 days"
implementation:
siem: "Splunk Enterprise Security with CIP content pack"
log_sources:
- "ESP boundary firewall logs"
- "EAP authentication logs"
- "BES Cyber Asset authentication success/failure"
- "Remote access session logs"
- "Malicious code detection events"
retention: "90 days online, 3 years archived"
R5_system_access:
description: "System Access Control"
requirements:
- "Enforce authentication for all interactive access"
- "Implement least-privilege access control"
- "Change default passwords"
- "Enforce password complexity (CIP-007-6 R5.5)"
- "Limit unsuccessful login attempts"
implementation:
password_policy:
min_length: 8
complexity: "Mixed case + numbers + special characters"
max_age_days: 365
lockout_threshold: 5
lockout_duration_minutes: 30
shared_accounts: "Document all shared/service accounts with authorization"Key Concepts
| Term | Definition |
|---|---|
| BES Cyber System | Group of one or more BES Cyber Assets that perform a reliability function for the Bulk Electric System |
| Electronic Security Perimeter (ESP) | Logical border surrounding a network containing BES Cyber Systems, with all traffic flowing through Electronic Access Points |
| Electronic Access Point (EAP) | Interface on the ESP boundary that controls traffic flowing in and out of the ESP |
| Intermediate System | System used for remote access that prevents direct connectivity to BES Cyber Assets (jump server) |
| Transient Cyber Asset | Device that is directly connected to a BES Cyber System for less than 30 consecutive calendar days (laptops, USB drives) |
| NERC Glossary | Official definitions used in CIP standards; precise terminology required for compliance |
Tools & Systems
- Tripwire Enterprise: Configuration compliance monitoring and file integrity monitoring for CIP-010 baseline management
- Splunk with CIP Content Pack: SIEM with pre-built CIP-007 security event monitoring dashboards and alerts
- Carbon Black App Control: Application allowlisting for HMI stations and BES cyber assets (CIP-007 R3)
- Trellix/McAfee ePO: Endpoint protection with OT-optimized scanning policies for BES cyber assets
Output Format
NERC CIP Compliance Assessment Report
=======================================
Entity: [Registered Entity Name]
Date: YYYY-MM-DD
Standards: CIP-002 through CIP-014
BES CYBER SYSTEM CATEGORIZATION:
High Impact: [N] systems
Medium Impact: [N] systems
Low Impact: [N] systems
COMPLIANCE STATUS BY STANDARD:
CIP-002: [Compliant/Partial/Non-Compliant]
CIP-005: [Status] - [N] gaps identified
CIP-007: [Status] - [N] gaps identified
CIP-010: [Status] - [N] gaps identified
CIP-013: [Status] - [N] gaps identifiedReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md1.5 KB
API Reference: Implementing NERC CIP Compliance Controls
NERC CIP Standards Summary
| Standard | Title | Focus |
|---|---|---|
| CIP-002 | BES Cyber System Categorization | Asset identification |
| CIP-003 | Security Management Controls | Policies, delegation |
| CIP-004 | Personnel and Training | Background checks, training |
| CIP-005 | Electronic Security Perimeters | Network boundaries, remote access |
| CIP-006 | Physical Security | Physical access controls |
| CIP-007 | Systems Security Management | Ports, patches, malware, logging |
| CIP-008 | Incident Reporting | Incident response plan |
| CIP-009 | Recovery Plans | Backup, recovery testing |
| CIP-010 | Configuration and Vulnerability | Baselines, vulnerability assessment |
| CIP-011 | Information Protection | BES Cyber System Information |
| CIP-013 | Supply Chain Risk Management | Vendor risk assessment |
CIP-005 ESP Requirements
| Requirement | Description |
|---|---|
| R1 | Define and document ESP boundaries |
| R1.3 | Deny-by-default firewall rules |
| R2 | MFA for interactive remote access |
| R2.3 | Encrypt remote sessions |
CIP-007 Patching Timeline
| Impact Level | Patch Cycle |
|---|---|
| High | 35 days from availability |
| Medium | 35 days from availability |
| Low | Documented mitigation plan |
References
- NERC CIP Standards: https://www.nerc.com/pa/Stand/Pages/CIPStandards.aspx
- NERC CIP v5/v7: https://www.nerc.com/pa/CI/tpv5impmntnstdy/Pages/default.aspx
Scripts 1
agent.py6.5 KB
#!/usr/bin/env python3
"""NERC CIP Compliance Agent - audits critical infrastructure against NERC CIP standards."""
import json
import argparse
import logging
import subprocess
from datetime import datetime
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
NERC_CIP_CONTROLS = {
"CIP-002": {"name": "BES Cyber System Categorization", "checks": [
"asset_inventory_complete", "impact_ratings_assigned", "annual_review_documented"
]},
"CIP-003": {"name": "Security Management Controls", "checks": [
"cyber_security_policy_exists", "senior_manager_designated", "delegation_documented"
]},
"CIP-004": {"name": "Personnel and Training", "checks": [
"security_awareness_training", "role_based_training", "personnel_risk_assessment",
"access_revocation_process"
]},
"CIP-005": {"name": "Electronic Security Perimeters", "checks": [
"esp_defined", "eap_controls_configured", "remote_access_encrypted",
"interactive_remote_access_mfa"
]},
"CIP-006": {"name": "Physical Security", "checks": [
"physical_security_plan", "visitor_control_program", "psp_access_monitoring"
]},
"CIP-007": {"name": "System Security Management", "checks": [
"ports_services_minimized", "patch_management_process", "malware_prevention",
"security_event_monitoring", "system_access_controls"
]},
"CIP-008": {"name": "Incident Reporting and Response", "checks": [
"incident_response_plan", "incident_response_testing", "reporting_procedures"
]},
"CIP-009": {"name": "Recovery Plans", "checks": [
"recovery_plans_exist", "backup_procedures", "recovery_testing_annual"
]},
"CIP-010": {"name": "Configuration Change Management", "checks": [
"baseline_configurations", "change_management_process", "vulnerability_assessments"
]},
"CIP-011": {"name": "Information Protection", "checks": [
"information_classification", "bcsi_protection", "bcsi_disposal"
]},
"CIP-013": {"name": "Supply Chain Risk Management", "checks": [
"supply_chain_plan", "vendor_risk_assessment", "vendor_notification_process"
]},
}
def check_esp_controls(target_ip=None):
"""Check Electronic Security Perimeter controls via network scan."""
findings = []
if target_ip:
cmd = ["nmap", "-sS", "-p", "1-1024", "--open", target_ip, "-oX", "-"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
open_ports = result.stdout.count("state=\"open\"")
if open_ports > 10:
findings.append({"control": "CIP-005", "issue": f"{open_ports} open ports on ESP boundary",
"severity": "high"})
return findings
def check_system_hardening():
"""Check CIP-007 system hardening controls."""
findings = []
svc_cmd = ["systemctl", "list-units", "--type=service", "--state=running", "--no-pager"]
result = subprocess.run(svc_cmd, capture_output=True, text=True, timeout=120)
service_count = len([l for l in result.stdout.split("\n") if ".service" in l])
if service_count > 50:
findings.append({"control": "CIP-007-R1", "issue": f"{service_count} running services (minimize unused)",
"severity": "medium"})
patch_cmd = ["apt", "list", "--upgradable"] if subprocess.run(["which", "apt"], capture_output=True, timeout=120).returncode == 0 else ["yum", "check-update"]
result = subprocess.run(patch_cmd, capture_output=True, text=True, timeout=120)
pending = len([l for l in result.stdout.split("\n") if l.strip() and not l.startswith("Listing")])
if pending > 0:
findings.append({"control": "CIP-007-R2", "issue": f"{pending} pending security patches",
"severity": "high"})
return findings
def audit_compliance_status(evidence_file=None):
"""Audit compliance status against all NERC CIP controls."""
evidence = {}
if evidence_file:
with open(evidence_file) as f:
evidence = json.load(f)
results = {}
for cip_id, control in NERC_CIP_CONTROLS.items():
check_results = {}
for check in control["checks"]:
status = evidence.get(cip_id, {}).get(check, "not_assessed")
check_results[check] = status
passed = sum(1 for v in check_results.values() if v == "pass")
total = len(check_results)
results[cip_id] = {
"name": control["name"],
"checks": check_results,
"passed": passed,
"total": total,
"compliance_rate": round(passed / max(total, 1) * 100, 1),
}
return results
def generate_report(compliance, esp_findings, hardening_findings):
total_checks = sum(r["total"] for r in compliance.values())
total_passed = sum(r["passed"] for r in compliance.values())
all_findings = esp_findings + hardening_findings
report = {
"timestamp": datetime.utcnow().isoformat(),
"framework": "NERC CIP v6/v7",
"overall_compliance_rate": round(total_passed / max(total_checks, 1) * 100, 1),
"total_controls_assessed": total_checks,
"total_passed": total_passed,
"cip_standard_results": compliance,
"technical_findings": all_findings,
"high_severity_findings": len([f for f in all_findings if f.get("severity") == "high"]),
}
return report
def main():
parser = argparse.ArgumentParser(description="NERC CIP Compliance Audit Agent")
parser.add_argument("--evidence-file", help="JSON evidence file with control assessment results")
parser.add_argument("--target-ip", help="ESP boundary IP to scan")
parser.add_argument("--skip-hardening", action="store_true", help="Skip system hardening checks")
parser.add_argument("--output", default="nerc_cip_report.json")
args = parser.parse_args()
compliance = audit_compliance_status(args.evidence_file)
esp_findings = check_esp_controls(args.target_ip) if args.target_ip else []
hardening = check_system_hardening() if not args.skip_hardening else []
report = generate_report(compliance, esp_findings, hardening)
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
logger.info("NERC CIP compliance: %.1f%% (%d/%d), %d findings",
report["overall_compliance_rate"], report["total_passed"],
report["total_controls_assessed"], len(report["technical_findings"]))
print(json.dumps(report, indent=2, default=str))
if __name__ == "__main__":
main()