mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 14:14:56 +03:00
184 lines
6.1 KiB
Python
184 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for scanning infrastructure with Tenable Nessus.
|
|
|
|
Interacts with the Nessus REST API to create scan policies,
|
|
launch scans, monitor progress, retrieve results, and generate
|
|
vulnerability reports with severity-based prioritization.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import time
|
|
import urllib3
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
requests = None
|
|
|
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
|
|
|
|
class NessusScanAgent:
|
|
"""Manages Nessus vulnerability scans via REST API."""
|
|
|
|
def __init__(self, host=None, username="admin",
|
|
password="", output_dir="./nessus_scan"):
|
|
self.base_url = (host or os.environ.get("NESSUS_URL", "https://localhost:8834")).rstrip("/")
|
|
self.username = username
|
|
self.password = password
|
|
self.token = None
|
|
self.output_dir = Path(output_dir)
|
|
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
def _req(self, method, path, data=None):
|
|
"""Make authenticated request to Nessus API."""
|
|
if not requests:
|
|
return {"error": "requests library required: pip install requests"}
|
|
headers = {"Content-Type": "application/json"}
|
|
if self.token:
|
|
headers["X-Cookie"] = f"token={self.token}"
|
|
url = f"{self.base_url}{path}"
|
|
resp = requests.request(method, url, json=data, headers=headers,
|
|
verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30) # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
|
|
try:
|
|
return resp.json()
|
|
except (json.JSONDecodeError, ValueError):
|
|
return {"status_code": resp.status_code, "text": resp.text[:200]}
|
|
|
|
def authenticate(self):
|
|
"""Authenticate and obtain session token."""
|
|
result = self._req("POST", "/session",
|
|
{"username": self.username, "password": self.password})
|
|
self.token = result.get("token")
|
|
return bool(self.token)
|
|
|
|
def list_scans(self):
|
|
"""List all configured scans."""
|
|
result = self._req("GET", "/scans")
|
|
scans = []
|
|
for s in result.get("scans", []):
|
|
scans.append({
|
|
"id": s.get("id"),
|
|
"name": s.get("name"),
|
|
"status": s.get("status"),
|
|
"last_modification_date": s.get("last_modification_date"),
|
|
})
|
|
return scans
|
|
|
|
def create_scan(self, name, targets, template_uuid=None):
|
|
"""Create a new scan configuration."""
|
|
data = {
|
|
"uuid": template_uuid or "ab4bacd2-05f6-425c-9d79-3f5a0a1f28b0",
|
|
"settings": {
|
|
"name": name,
|
|
"text_targets": targets,
|
|
"enabled": True,
|
|
"launch": "ON_DEMAND",
|
|
},
|
|
}
|
|
return self._req("POST", "/scans", data)
|
|
|
|
def launch_scan(self, scan_id):
|
|
"""Launch a configured scan."""
|
|
return self._req("POST", f"/scans/{scan_id}/launch")
|
|
|
|
def get_scan_status(self, scan_id):
|
|
"""Get current scan status."""
|
|
result = self._req("GET", f"/scans/{scan_id}")
|
|
info = result.get("info", {})
|
|
return {
|
|
"status": info.get("status"),
|
|
"host_count": info.get("hostcount", 0),
|
|
"name": info.get("name"),
|
|
}
|
|
|
|
def get_scan_results(self, scan_id):
|
|
"""Retrieve scan results with vulnerability details."""
|
|
result = self._req("GET", f"/scans/{scan_id}")
|
|
hosts = []
|
|
for h in result.get("hosts", []):
|
|
hosts.append({
|
|
"hostname": h.get("hostname"),
|
|
"host_id": h.get("host_id"),
|
|
"critical": h.get("critical", 0),
|
|
"high": h.get("high", 0),
|
|
"medium": h.get("medium", 0),
|
|
"low": h.get("low", 0),
|
|
"info": h.get("info", 0),
|
|
})
|
|
|
|
vulns = []
|
|
for v in result.get("vulnerabilities", []):
|
|
vulns.append({
|
|
"plugin_id": v.get("plugin_id"),
|
|
"plugin_name": v.get("plugin_name"),
|
|
"severity": v.get("severity"),
|
|
"count": v.get("count", 0),
|
|
"family": v.get("plugin_family"),
|
|
})
|
|
|
|
return {
|
|
"scan_id": scan_id,
|
|
"hosts": hosts,
|
|
"vulnerabilities": sorted(vulns, key=lambda x: x.get("severity", 0), reverse=True),
|
|
"total_vulns": len(vulns),
|
|
}
|
|
|
|
def export_scan(self, scan_id, fmt="nessus"):
|
|
"""Export scan results in specified format."""
|
|
result = self._req("POST", f"/scans/{scan_id}/export", {"format": fmt})
|
|
file_id = result.get("file")
|
|
if not file_id:
|
|
return {"error": "Export failed"}
|
|
|
|
for _ in range(60):
|
|
status = self._req("GET", f"/scans/{scan_id}/export/{file_id}/status")
|
|
if status.get("status") == "ready":
|
|
break
|
|
time.sleep(5)
|
|
|
|
return {"file_id": file_id, "format": fmt, "status": "ready"}
|
|
|
|
def generate_report(self, scan_id):
|
|
results = self.get_scan_results(scan_id)
|
|
report = {
|
|
"report_date": datetime.utcnow().isoformat(),
|
|
"scan_id": scan_id,
|
|
"results": results,
|
|
}
|
|
out = self.output_dir / "nessus_report.json"
|
|
with open(out, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
print(json.dumps(report, indent=2))
|
|
return report
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 3:
|
|
print("Usage: agent.py <nessus_url> <scan_id> [--user admin] [--pass password]")
|
|
sys.exit(1)
|
|
|
|
host = sys.argv[1]
|
|
scan_id = int(sys.argv[2])
|
|
user = "admin"
|
|
password = ""
|
|
if "--user" in sys.argv:
|
|
user = sys.argv[sys.argv.index("--user") + 1]
|
|
if "--pass" in sys.argv:
|
|
password = sys.argv[sys.argv.index("--pass") + 1]
|
|
|
|
agent = NessusScanAgent(host, user, password)
|
|
if agent.authenticate():
|
|
agent.generate_report(scan_id)
|
|
else:
|
|
print("Authentication failed")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|