mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
181 lines
6.8 KiB
Python
181 lines
6.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Authenticated vulnerability scan orchestration agent using Nessus API."""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import argparse
|
|
from datetime import datetime
|
|
|
|
try:
|
|
import requests
|
|
import urllib3
|
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
except ImportError:
|
|
print("Install: pip install requests")
|
|
sys.exit(1)
|
|
|
|
|
|
class NessusClient:
|
|
"""Client for Tenable Nessus REST API."""
|
|
|
|
def __init__(self, url, access_key, secret_key):
|
|
self.base_url = url.rstrip("/")
|
|
self.headers = {
|
|
"X-ApiKeys": f"accessKey={access_key}; secretKey={secret_key}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
def _get(self, path, params=None):
|
|
resp = requests.get(f"{self.base_url}{path}", headers=self.headers,
|
|
params=params,
|
|
verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30) # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
def _post(self, path, data=None):
|
|
resp = requests.post(f"{self.base_url}{path}", headers=self.headers,
|
|
json=data,
|
|
verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30) # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
def list_scans(self):
|
|
return self._get("/scans").get("scans", [])
|
|
|
|
def get_scan_details(self, scan_id):
|
|
return self._get(f"/scans/{scan_id}")
|
|
|
|
def list_policies(self):
|
|
return self._get("/policies").get("policies", [])
|
|
|
|
def list_credentials(self):
|
|
return self._get("/credentials").get("credentials", [])
|
|
|
|
def get_scan_results(self, scan_id):
|
|
details = self.get_scan_details(scan_id)
|
|
hosts = details.get("hosts", [])
|
|
vulns = details.get("vulnerabilities", [])
|
|
return {"hosts": hosts, "vulnerabilities": vulns, "info": details.get("info", {})}
|
|
|
|
def get_host_vulnerabilities(self, scan_id, host_id):
|
|
return self._get(f"/scans/{scan_id}/hosts/{host_id}")
|
|
|
|
def export_scan(self, scan_id, fmt="nessus"):
|
|
data = {"format": fmt}
|
|
resp = self._post(f"/scans/{scan_id}/export", data)
|
|
return resp.get("file", 0)
|
|
|
|
|
|
def analyze_scan_results(results):
|
|
"""Analyze scan results and categorize findings."""
|
|
vulns = results.get("vulnerabilities", [])
|
|
severity_map = {0: "Info", 1: "Low", 2: "Medium", 3: "High", 4: "Critical"}
|
|
severity_counts = {"Critical": 0, "High": 0, "Medium": 0, "Low": 0, "Info": 0}
|
|
|
|
categorized = []
|
|
for v in vulns:
|
|
sev = severity_map.get(v.get("severity", 0), "Info")
|
|
severity_counts[sev] += 1
|
|
categorized.append({
|
|
"plugin_id": v.get("plugin_id", 0),
|
|
"plugin_name": v.get("plugin_name", ""),
|
|
"severity": sev,
|
|
"severity_index": v.get("severity", 0),
|
|
"count": v.get("count", 0),
|
|
"family": v.get("plugin_family", ""),
|
|
})
|
|
|
|
categorized.sort(key=lambda x: x["severity_index"], reverse=True)
|
|
return {"severity_counts": severity_counts, "vulnerabilities": categorized}
|
|
|
|
|
|
def audit_credential_coverage(results):
|
|
"""Check if authenticated scan achieved credential coverage."""
|
|
findings = []
|
|
hosts = results.get("hosts", [])
|
|
for host in hosts:
|
|
host_info = host.get("info", {})
|
|
credentialed = host.get("credentialed_checks_running", "")
|
|
if not credentialed or credentialed == "no":
|
|
findings.append({
|
|
"host": host.get("hostname", host.get("host_id", "")),
|
|
"issue": "Credentialed checks not running — scan is unauthenticated",
|
|
"severity": "HIGH",
|
|
"detail": "Configure valid credentials for this host",
|
|
})
|
|
return findings
|
|
|
|
|
|
def compare_auth_vs_unauth(auth_results, unauth_results):
|
|
"""Compare authenticated vs unauthenticated scan finding counts."""
|
|
auth_vulns = len(auth_results.get("vulnerabilities", []))
|
|
unauth_vulns = len(unauth_results.get("vulnerabilities", []))
|
|
improvement = ((auth_vulns - unauth_vulns) / max(unauth_vulns, 1)) * 100
|
|
return {
|
|
"authenticated_findings": auth_vulns,
|
|
"unauthenticated_findings": unauth_vulns,
|
|
"improvement_pct": round(improvement, 1),
|
|
"additional_findings": auth_vulns - unauth_vulns,
|
|
}
|
|
|
|
|
|
def run_audit(args):
|
|
"""Execute authenticated vulnerability scan audit."""
|
|
print(f"\n{'='*60}")
|
|
print(f" AUTHENTICATED VULNERABILITY SCAN AUDIT")
|
|
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
|
|
print(f"{'='*60}\n")
|
|
|
|
client = NessusClient(args.nessus_url, args.access_key, args.secret_key)
|
|
report = {}
|
|
|
|
scans = client.list_scans()
|
|
report["total_scans"] = len(scans) if scans else 0
|
|
print(f"--- AVAILABLE SCANS ({report['total_scans']}) ---")
|
|
for s in (scans or [])[:10]:
|
|
print(f" [{s.get('status','')}] {s.get('name','')}: {s.get('id','')}")
|
|
|
|
if args.scan_id:
|
|
results = client.get_scan_results(args.scan_id)
|
|
analysis = analyze_scan_results(results)
|
|
report["analysis"] = analysis
|
|
counts = analysis["severity_counts"]
|
|
print(f"\n--- SCAN RESULTS (ID: {args.scan_id}) ---")
|
|
print(f" Critical: {counts['Critical']} | High: {counts['High']} | "
|
|
f"Medium: {counts['Medium']} | Low: {counts['Low']}")
|
|
print(f"\n--- TOP VULNERABILITIES ---")
|
|
for v in analysis["vulnerabilities"][:15]:
|
|
print(f" [{v['severity']}] {v['plugin_name'][:70]} (x{v['count']})")
|
|
|
|
cred_check = audit_credential_coverage(results)
|
|
report["credential_coverage"] = cred_check
|
|
if cred_check:
|
|
print(f"\n--- CREDENTIAL COVERAGE ISSUES ({len(cred_check)}) ---")
|
|
for c in cred_check:
|
|
print(f" [{c['severity']}] {c['host']}: {c['issue']}")
|
|
else:
|
|
print(f"\n Credential coverage: All hosts authenticated")
|
|
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Authenticated Vulnerability Scan Agent")
|
|
parser.add_argument("--nessus-url", required=True, help="Nessus server URL")
|
|
parser.add_argument("--access-key", required=True, help="Nessus API access key")
|
|
parser.add_argument("--secret-key", required=True, help="Nessus API secret key")
|
|
parser.add_argument("--scan-id", type=int, help="Scan ID to analyze results")
|
|
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()
|