mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 14:14: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
198 lines
7.0 KiB
Python
198 lines
7.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Vulnerability scanning agent using the Nessus REST API."""
|
|
|
|
import json
|
|
import sys
|
|
import time
|
|
import os
|
|
import urllib3
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
print("Install: pip install requests")
|
|
sys.exit(1)
|
|
|
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
|
|
|
|
class NessusAPI:
|
|
def __init__(self, url=None, access_key=None, secret_key=None):
|
|
url = url or os.environ.get("NESSUS_URL", "https://localhost:8834")
|
|
self.url = url.rstrip("/")
|
|
self.session = requests.Session()
|
|
self.session.verify = False
|
|
if access_key and secret_key:
|
|
self.session.headers.update({
|
|
"X-ApiKeys": f"accessKey={access_key}; secretKey={secret_key}"
|
|
})
|
|
|
|
def _get(self, endpoint):
|
|
resp = self.session.get(f"{self.url}{endpoint}", timeout=30)
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
def _post(self, endpoint, data=None):
|
|
resp = self.session.post(f"{self.url}{endpoint}", json=data, timeout=30)
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
def _put(self, endpoint, data=None):
|
|
resp = self.session.put(f"{self.url}{endpoint}", json=data, timeout=30)
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
def get_server_status(self):
|
|
return self._get("/server/status")
|
|
|
|
def list_scans(self):
|
|
data = self._get("/scans")
|
|
scans = []
|
|
for scan in data.get("scans", []):
|
|
scans.append({
|
|
"id": scan["id"], "name": scan["name"],
|
|
"status": scan["status"],
|
|
"folder_id": scan.get("folder_id"),
|
|
})
|
|
return scans
|
|
|
|
def get_scan_details(self, scan_id):
|
|
data = self._get(f"/scans/{scan_id}")
|
|
info = data.get("info", {})
|
|
hosts = data.get("hosts", [])
|
|
vulns = data.get("vulnerabilities", [])
|
|
return {
|
|
"scan_id": scan_id,
|
|
"name": info.get("name"),
|
|
"status": info.get("status"),
|
|
"host_count": info.get("hostcount", len(hosts)),
|
|
"targets": info.get("targets"),
|
|
"start_time": info.get("scanner_start"),
|
|
"end_time": info.get("scanner_end"),
|
|
"policy": info.get("policy"),
|
|
"severity_counts": {
|
|
"critical": sum(1 for v in vulns if v.get("severity") == 4),
|
|
"high": sum(1 for v in vulns if v.get("severity") == 3),
|
|
"medium": sum(1 for v in vulns if v.get("severity") == 2),
|
|
"low": sum(1 for v in vulns if v.get("severity") == 1),
|
|
"info": sum(1 for v in vulns if v.get("severity") == 0),
|
|
},
|
|
"vulnerabilities": [
|
|
{
|
|
"plugin_id": v["plugin_id"],
|
|
"name": v["plugin_name"],
|
|
"severity": v["severity"],
|
|
"count": v["count"],
|
|
"family": v.get("plugin_family"),
|
|
}
|
|
for v in sorted(vulns, key=lambda x: -x.get("severity", 0))[:50]
|
|
],
|
|
}
|
|
|
|
def create_scan(self, name, targets, policy_id=None, template="advanced"):
|
|
templates = self._get("/editor/scan/templates")
|
|
template_uuid = None
|
|
for t in templates.get("templates", []):
|
|
if t["name"] == template:
|
|
template_uuid = t["uuid"]
|
|
break
|
|
if not template_uuid:
|
|
template_uuid = templates["templates"][0]["uuid"]
|
|
scan_config = {
|
|
"uuid": template_uuid,
|
|
"settings": {
|
|
"name": name,
|
|
"text_targets": targets,
|
|
"launch_now": False,
|
|
},
|
|
}
|
|
if policy_id:
|
|
scan_config["settings"]["policy_id"] = policy_id
|
|
return self._post("/scans", scan_config)
|
|
|
|
def launch_scan(self, scan_id):
|
|
return self._post(f"/scans/{scan_id}/launch")
|
|
|
|
def get_scan_status(self, scan_id):
|
|
data = self._get(f"/scans/{scan_id}")
|
|
return data.get("info", {}).get("status", "unknown")
|
|
|
|
def wait_for_scan(self, scan_id, poll_interval=30, timeout=7200):
|
|
elapsed = 0
|
|
while elapsed < timeout:
|
|
status = self.get_scan_status(scan_id)
|
|
if status == "completed":
|
|
return True
|
|
if status in ("canceled", "aborted"):
|
|
return False
|
|
time.sleep(poll_interval)
|
|
elapsed += poll_interval
|
|
return False
|
|
|
|
def export_scan(self, scan_id, fmt="csv"):
|
|
data = self._post(f"/scans/{scan_id}/export", {"format": fmt})
|
|
file_id = data.get("file")
|
|
if not file_id:
|
|
return None
|
|
while True:
|
|
status = self._get(f"/scans/{scan_id}/export/{file_id}/status")
|
|
if status.get("status") == "ready":
|
|
break
|
|
time.sleep(5)
|
|
resp = self.session.get(f"{self.url}/scans/{scan_id}/export/{file_id}/download", timeout=30)
|
|
return resp.content
|
|
|
|
def check_auth_status(self, scan_id):
|
|
"""Check if authenticated scanning succeeded per host."""
|
|
data = self._get(f"/scans/{scan_id}")
|
|
auth_results = []
|
|
for host in data.get("hosts", []):
|
|
host_id = host["host_id"]
|
|
host_detail = self._get(f"/scans/{scan_id}/hosts/{host_id}")
|
|
auth_info = None
|
|
for vuln in host_detail.get("vulnerabilities", []):
|
|
if vuln["plugin_id"] == 19506:
|
|
auth_info = vuln
|
|
break
|
|
auth_results.append({
|
|
"hostname": host.get("hostname"),
|
|
"host_id": host_id,
|
|
"critical": host.get("critical", 0),
|
|
"high": host.get("high", 0),
|
|
"authenticated": auth_info is not None,
|
|
})
|
|
return auth_results
|
|
|
|
|
|
def print_scan_report(details):
|
|
print("Vulnerability Scan Report")
|
|
print("=" * 50)
|
|
print(f"Scan: {details['name']}")
|
|
print(f"Status: {details['status']}")
|
|
print(f"Hosts: {details['host_count']}")
|
|
print(f"Targets: {details['targets']}")
|
|
sev = details["severity_counts"]
|
|
print(f"\nSeverity Summary:")
|
|
print(f" Critical: {sev['critical']}")
|
|
print(f" High: {sev['high']}")
|
|
print(f" Medium: {sev['medium']}")
|
|
print(f" Low: {sev['low']}")
|
|
print(f" Info: {sev['info']}")
|
|
print(f"\nTop Vulnerabilities:")
|
|
for v in details["vulnerabilities"][:15]:
|
|
sev_label = {4: "CRIT", 3: "HIGH", 2: "MED", 1: "LOW", 0: "INFO"}.get(v["severity"], "?")
|
|
print(f" [{sev_label}] {v['name']} (plugin {v['plugin_id']}, count: {v['count']})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
nessus_url = os.environ.get("NESSUS_URL", "https://localhost:8834")
|
|
access_key = os.environ.get("NESSUS_ACCESS_KEY", "")
|
|
secret_key = os.environ.get("NESSUS_SECRET_KEY", "")
|
|
api = NessusAPI(nessus_url, access_key, secret_key)
|
|
scans = api.list_scans()
|
|
if scans:
|
|
details = api.get_scan_details(scans[0]["id"])
|
|
print_scan_report(details)
|
|
else:
|
|
print("No scans found. Create one with api.create_scan()")
|