mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-09-12 11:20:51 +03:00
Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- Add scripts/agent.py and references/api-reference.md to all remaining skills - Update all 648 LICENSE files: copyright now reads 'Mahipal' - Add implementing-security-monitoring-with-datadog (new skill with full anatomy) - All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for performing ICS asset discovery with Claroty xDome/CTD API."""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
requests = None
|
||||
|
||||
|
||||
class ClarotyClient:
|
||||
"""Client for Claroty xDome / Continuous Threat Detection API."""
|
||||
|
||||
def __init__(self, base_url, api_token):
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update({
|
||||
"Authorization": f"Bearer {api_token}",
|
||||
"Content-Type": "application/json",
|
||||
})
|
||||
|
||||
def get_assets(self, asset_type=None, limit=100):
|
||||
"""Retrieve discovered OT/IoT assets."""
|
||||
params = {"limit": limit}
|
||||
if asset_type:
|
||||
params["type"] = asset_type
|
||||
resp = self.session.get(f"{self.base_url}/api/v1/assets", params=params, timeout=30)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
def get_asset_detail(self, asset_id):
|
||||
"""Get detailed info for a specific asset."""
|
||||
resp = self.session.get(f"{self.base_url}/api/v1/assets/{asset_id}", timeout=30)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
def get_vulnerabilities(self, severity=None, limit=100):
|
||||
"""Retrieve vulnerabilities found on OT assets."""
|
||||
params = {"limit": limit}
|
||||
if severity:
|
||||
params["severity"] = severity
|
||||
resp = self.session.get(f"{self.base_url}/api/v1/vulnerabilities", params=params, timeout=30)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
def get_alerts(self, status="active", limit=50):
|
||||
"""Retrieve active security alerts."""
|
||||
params = {"status": status, "limit": limit}
|
||||
resp = self.session.get(f"{self.base_url}/api/v1/alerts", params=params, timeout=30)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
def get_network_segments(self):
|
||||
"""Retrieve network segmentation topology."""
|
||||
resp = self.session.get(f"{self.base_url}/api/v1/network/segments", timeout=30)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def discover_assets(base_url, token, asset_type=None, limit=100):
|
||||
"""Run asset discovery and categorize results."""
|
||||
client = ClarotyClient(base_url, token)
|
||||
data = client.get_assets(asset_type, limit)
|
||||
assets = data.get("assets", data.get("results", []))
|
||||
categories = {}
|
||||
vendors = {}
|
||||
for asset in assets:
|
||||
cat = asset.get("type", asset.get("category", "unknown"))
|
||||
categories[cat] = categories.get(cat, 0) + 1
|
||||
vendor = asset.get("vendor", asset.get("manufacturer", "unknown"))
|
||||
vendors[vendor] = vendors.get(vendor, 0) + 1
|
||||
critical = [a for a in assets if a.get("criticality", "").lower() in ("critical", "high")]
|
||||
return {
|
||||
"total_assets": len(assets),
|
||||
"by_category": categories,
|
||||
"by_vendor": dict(sorted(vendors.items(), key=lambda x: -x[1])[:20]),
|
||||
"critical_assets": len(critical),
|
||||
"assets": [{"id": a.get("id"), "name": a.get("name"), "type": a.get("type"),
|
||||
"ip": a.get("ip_address", a.get("ip")), "vendor": a.get("vendor"),
|
||||
"firmware": a.get("firmware_version", ""), "criticality": a.get("criticality")}
|
||||
for a in assets[:50]],
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
|
||||
|
||||
def assess_vulnerabilities(base_url, token, severity=None, limit=100):
|
||||
"""Retrieve and prioritize OT vulnerabilities."""
|
||||
client = ClarotyClient(base_url, token)
|
||||
data = client.get_vulnerabilities(severity, limit)
|
||||
vulns = data.get("vulnerabilities", data.get("results", []))
|
||||
by_severity = {}
|
||||
for v in vulns:
|
||||
s = v.get("severity", "unknown")
|
||||
by_severity[s] = by_severity.get(s, 0) + 1
|
||||
return {
|
||||
"total_vulnerabilities": len(vulns),
|
||||
"by_severity": by_severity,
|
||||
"vulnerabilities": [{"cve": v.get("cve_id"), "severity": v.get("severity"),
|
||||
"asset": v.get("asset_name", v.get("asset_id")),
|
||||
"description": v.get("description", "")[:200]}
|
||||
for v in vulns[:30]],
|
||||
}
|
||||
|
||||
|
||||
def get_alerts_summary(base_url, token, status="active"):
|
||||
"""Get security alert summary."""
|
||||
client = ClarotyClient(base_url, token)
|
||||
data = client.get_alerts(status)
|
||||
alerts = data.get("alerts", data.get("results", []))
|
||||
by_type = {}
|
||||
for a in alerts:
|
||||
t = a.get("alert_type", a.get("type", "unknown"))
|
||||
by_type[t] = by_type.get(t, 0) + 1
|
||||
return {
|
||||
"total_alerts": len(alerts),
|
||||
"status": status,
|
||||
"by_type": by_type,
|
||||
"alerts": [{"id": a.get("id"), "type": a.get("alert_type"),
|
||||
"severity": a.get("severity"), "description": a.get("description", "")[:150],
|
||||
"asset": a.get("asset_name")} for a in alerts[:20]],
|
||||
}
|
||||
|
||||
|
||||
def network_topology(base_url, token):
|
||||
"""Map OT network segments."""
|
||||
client = ClarotyClient(base_url, token)
|
||||
data = client.get_network_segments()
|
||||
segments = data.get("segments", data.get("results", []))
|
||||
return {
|
||||
"total_segments": len(segments),
|
||||
"segments": [{"name": s.get("name"), "subnet": s.get("subnet"),
|
||||
"asset_count": s.get("asset_count", 0),
|
||||
"zone": s.get("zone", s.get("purdue_level", ""))}
|
||||
for s in segments],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
if not requests:
|
||||
print(json.dumps({"error": "requests not installed"}))
|
||||
return
|
||||
parser = argparse.ArgumentParser(description="ICS Asset Discovery with Claroty Agent")
|
||||
parser.add_argument("--url", required=True, help="Claroty xDome/CTD base URL")
|
||||
parser.add_argument("--token", required=True, help="API token")
|
||||
sub = parser.add_subparsers(dest="command")
|
||||
a = sub.add_parser("assets", help="Discover OT/IoT assets")
|
||||
a.add_argument("--type", help="Filter by asset type (PLC, HMI, RTU, etc.)")
|
||||
a.add_argument("--limit", type=int, default=100)
|
||||
v = sub.add_parser("vulns", help="List vulnerabilities")
|
||||
v.add_argument("--severity", help="Filter by severity")
|
||||
v.add_argument("--limit", type=int, default=100)
|
||||
sub.add_parser("alerts", help="Get active alerts")
|
||||
sub.add_parser("topology", help="Map network segments")
|
||||
args = parser.parse_args()
|
||||
if args.command == "assets":
|
||||
result = discover_assets(args.url, args.token, args.type, args.limit)
|
||||
elif args.command == "vulns":
|
||||
result = assess_vulnerabilities(args.url, args.token, args.severity, args.limit)
|
||||
elif args.command == "alerts":
|
||||
result = get_alerts_summary(args.url, args.token)
|
||||
elif args.command == "topology":
|
||||
result = network_topology(args.url, args.token)
|
||||
else:
|
||||
parser.print_help()
|
||||
return
|
||||
print(json.dumps(result, indent=2, default=str))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user