mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 13:44:56 +03:00
c21af3347e
- 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
177 lines
6.6 KiB
Python
177 lines
6.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Software-Defined Perimeter (SDP) deployment audit agent."""
|
|
|
|
import json
|
|
import sys
|
|
import argparse
|
|
import socket
|
|
import ssl
|
|
from datetime import datetime
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
print("Install: pip install requests")
|
|
sys.exit(1)
|
|
|
|
|
|
def check_spa_port(host, port, timeout=5):
|
|
"""Check if a port responds to standard TCP connect (should be dark in SDP)."""
|
|
try:
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.settimeout(timeout)
|
|
result = sock.connect_ex((host, port))
|
|
sock.close()
|
|
return {"host": host, "port": port, "open": result == 0}
|
|
except socket.error as e:
|
|
return {"host": host, "port": port, "open": False, "error": str(e)}
|
|
|
|
|
|
def audit_dark_ports(host, ports):
|
|
"""Verify SDP ports are invisible to unauthorized scanners."""
|
|
results = []
|
|
for port in ports:
|
|
scan = check_spa_port(host, port)
|
|
if scan.get("open"):
|
|
scan["finding"] = "Port visible without SPA — SDP not enforced"
|
|
scan["severity"] = "HIGH"
|
|
else:
|
|
scan["finding"] = "Port dark — SDP enforced"
|
|
scan["severity"] = "INFO"
|
|
results.append(scan)
|
|
return results
|
|
|
|
|
|
def check_tls_mutual_auth(host, port, client_cert=None, client_key=None):
|
|
"""Verify mutual TLS authentication on SDP controller."""
|
|
result = {"host": host, "port": port}
|
|
try:
|
|
ctx = ssl.create_default_context()
|
|
if client_cert and client_key:
|
|
ctx.load_cert_chain(client_cert, client_key)
|
|
with ctx.wrap_socket(socket.socket(), server_hostname=host) as s:
|
|
s.settimeout(10)
|
|
s.connect((host, port))
|
|
cert = s.getpeercert()
|
|
result["tls_version"] = s.version()
|
|
result["cipher"] = s.cipher()[0]
|
|
result["server_cn"] = dict(x[0] for x in cert.get("subject", ()))
|
|
result["mtls_enforced"] = client_cert is not None
|
|
except ssl.SSLError as e:
|
|
result["error"] = str(e)
|
|
if "CERTIFICATE_REQUIRED" in str(e):
|
|
result["mtls_enforced"] = True
|
|
result["finding"] = "Server requires client certificate — mTLS enforced"
|
|
except Exception as e:
|
|
result["error"] = str(e)
|
|
return result
|
|
|
|
|
|
class SDPControllerClient:
|
|
"""Client for SDP controller REST API (e.g., Appgate SDP)."""
|
|
|
|
def __init__(self, controller_url, username, password):
|
|
self.base_url = controller_url.rstrip("/")
|
|
self.session = requests.Session()
|
|
self._authenticate(username, password)
|
|
|
|
def _authenticate(self, username, password):
|
|
resp = self.session.post(f"{self.base_url}/admin/login", json={
|
|
"providerName": "local",
|
|
"username": username,
|
|
"password": password,
|
|
}, timeout=15, verify=True)
|
|
resp.raise_for_status()
|
|
token = resp.json().get("token", "")
|
|
self.session.headers.update({"Authorization": f"Bearer {token}"})
|
|
|
|
def list_sites(self):
|
|
resp = self.session.get(f"{self.base_url}/admin/sites", timeout=15)
|
|
resp.raise_for_status()
|
|
return resp.json().get("data", [])
|
|
|
|
def list_policies(self):
|
|
resp = self.session.get(f"{self.base_url}/admin/policies", timeout=15)
|
|
resp.raise_for_status()
|
|
return resp.json().get("data", [])
|
|
|
|
def list_entitlements(self):
|
|
resp = self.session.get(f"{self.base_url}/admin/entitlements", timeout=15)
|
|
resp.raise_for_status()
|
|
return resp.json().get("data", [])
|
|
|
|
def list_appliances(self):
|
|
resp = self.session.get(f"{self.base_url}/admin/appliances", timeout=15)
|
|
resp.raise_for_status()
|
|
return resp.json().get("data", [])
|
|
|
|
|
|
def run_audit(args):
|
|
"""Execute SDP deployment audit."""
|
|
print(f"\n{'='*60}")
|
|
print(f" SOFTWARE-DEFINED PERIMETER AUDIT")
|
|
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
|
|
print(f"{'='*60}\n")
|
|
|
|
report = {}
|
|
|
|
if args.scan_host:
|
|
ports = [int(p) for p in args.ports.split(",")] if args.ports else [22, 443, 8443, 3389]
|
|
dark_results = audit_dark_ports(args.scan_host, ports)
|
|
report["dark_port_scan"] = dark_results
|
|
print(f"--- DARK PORT SCAN ({args.scan_host}) ---")
|
|
for r in dark_results:
|
|
status = "OPEN" if r["open"] else "DARK"
|
|
print(f" Port {r['port']}: {status} — {r['finding']}")
|
|
|
|
if args.mtls_host:
|
|
mtls = check_tls_mutual_auth(args.mtls_host, args.mtls_port or 443,
|
|
args.client_cert, args.client_key)
|
|
report["mtls_check"] = mtls
|
|
print(f"\n--- MUTUAL TLS CHECK ---")
|
|
print(f" Host: {mtls['host']}:{mtls['port']}")
|
|
print(f" mTLS Enforced: {mtls.get('mtls_enforced', 'unknown')}")
|
|
if mtls.get("tls_version"):
|
|
print(f" TLS Version: {mtls['tls_version']}")
|
|
|
|
if args.controller_url and args.username and args.password:
|
|
client = SDPControllerClient(args.controller_url, args.username, args.password)
|
|
appliances = client.list_appliances()
|
|
report["appliances"] = len(appliances)
|
|
print(f"\n--- SDP APPLIANCES ({len(appliances)}) ---")
|
|
for a in appliances[:10]:
|
|
print(f" {a.get('name', '')}: {a.get('function', '')} ({a.get('state', '')})")
|
|
|
|
entitlements = client.list_entitlements()
|
|
report["entitlements"] = len(entitlements)
|
|
print(f"\n--- ENTITLEMENTS ({len(entitlements)}) ---")
|
|
for e in entitlements[:10]:
|
|
print(f" {e.get('name', '')}: {e.get('site', '')} -> {e.get('actions', [])}")
|
|
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="SDP Deployment Audit")
|
|
parser.add_argument("--scan-host", help="Host to scan for dark ports")
|
|
parser.add_argument("--ports", help="Comma-separated ports to scan (default: 22,443,8443,3389)")
|
|
parser.add_argument("--mtls-host", help="Host to check mutual TLS")
|
|
parser.add_argument("--mtls-port", type=int, default=443, help="mTLS port")
|
|
parser.add_argument("--client-cert", help="Client certificate for mTLS test")
|
|
parser.add_argument("--client-key", help="Client key for mTLS test")
|
|
parser.add_argument("--controller-url", help="SDP controller URL (Appgate)")
|
|
parser.add_argument("--username", help="Controller admin username")
|
|
parser.add_argument("--password", help="Controller admin password")
|
|
parser.add_argument("--output", help="Save report to JSON file")
|
|
args = parser.parse_args()
|
|
|
|
report = run_audit(args)
|
|
if args.output:
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(f"\n[+] Report saved to {args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|