mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 06:04: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
193 lines
7.4 KiB
Python
193 lines
7.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for implementing endpoint detection with Wazuh.
|
|
|
|
Manages Wazuh agents, queries alerts, tests custom decoder/rule
|
|
logic via logtest, and audits endpoint coverage using the
|
|
Wazuh REST API.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
try:
|
|
import requests
|
|
from requests.auth import HTTPBasicAuth
|
|
except ImportError:
|
|
requests = None
|
|
|
|
|
|
class WazuhDetectionAgent:
|
|
"""Manages Wazuh endpoint detection via its REST API."""
|
|
|
|
def __init__(self, wazuh_url, username, password,
|
|
output_dir="./wazuh_detection"):
|
|
self.base_url = wazuh_url.rstrip("/")
|
|
self.output_dir = Path(output_dir)
|
|
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
self.findings = []
|
|
self.token = self._authenticate(username, password)
|
|
|
|
def _authenticate(self, username, password):
|
|
"""Authenticate and obtain JWT token."""
|
|
if not requests:
|
|
return None
|
|
try:
|
|
resp = requests.post(
|
|
f"{self.base_url}/security/user/authenticate",
|
|
auth=HTTPBasicAuth(username, password),
|
|
verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=10, # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
|
|
)
|
|
if resp.status_code == 200:
|
|
return resp.json().get("data", {}).get("token")
|
|
except requests.RequestException:
|
|
pass
|
|
return None
|
|
|
|
def _api(self, method, path, params=None, data=None):
|
|
if not requests or not self.token:
|
|
return None
|
|
try:
|
|
resp = requests.request(
|
|
method, f"{self.base_url}{path}",
|
|
headers={"Authorization": f"Bearer {self.token}"},
|
|
params=params, json=data, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=15, # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
|
|
)
|
|
return resp.json() if resp.status_code == 200 else None
|
|
except requests.RequestException:
|
|
return None
|
|
|
|
def list_agents(self):
|
|
"""List all registered Wazuh agents with status."""
|
|
data = self._api("GET", "/agents", params={"limit": 500, "select": "id,name,status,os.name,os.version,version,lastKeepAlive,ip"})
|
|
if not data:
|
|
return []
|
|
agents = data.get("data", {}).get("affected_items", [])
|
|
disconnected = [a for a in agents if a.get("status") == "disconnected"]
|
|
if disconnected:
|
|
self.findings.append({
|
|
"severity": "medium", "type": "Disconnected Agents",
|
|
"detail": f"{len(disconnected)} agents disconnected",
|
|
})
|
|
return agents
|
|
|
|
def get_agent_summary(self):
|
|
"""Get agent status summary counts."""
|
|
data = self._api("GET", "/agents/summary/status")
|
|
if data:
|
|
return data.get("data", {})
|
|
return {}
|
|
|
|
def query_alerts(self, limit=20, level_min=10):
|
|
"""Query recent high-severity alerts."""
|
|
data = self._api("GET", "/alerts", params={
|
|
"limit": limit, "sort": "-timestamp",
|
|
"q": f"rule.level>={level_min}",
|
|
})
|
|
if not data:
|
|
return []
|
|
alerts = data.get("data", {}).get("affected_items", [])
|
|
return [{
|
|
"id": a.get("id"),
|
|
"timestamp": a.get("timestamp"),
|
|
"rule_id": a.get("rule", {}).get("id"),
|
|
"rule_description": a.get("rule", {}).get("description"),
|
|
"rule_level": a.get("rule", {}).get("level"),
|
|
"agent_name": a.get("agent", {}).get("name"),
|
|
"agent_id": a.get("agent", {}).get("id"),
|
|
} for a in alerts]
|
|
|
|
def get_rules_summary(self):
|
|
"""Get summary of active detection rules."""
|
|
data = self._api("GET", "/rules", params={"limit": 500, "select": "id,description,level,groups"})
|
|
if not data:
|
|
return {"total": 0}
|
|
rules = data.get("data", {}).get("affected_items", [])
|
|
total = data.get("data", {}).get("total_affected_items", len(rules))
|
|
levels = {}
|
|
for r in rules:
|
|
lvl = str(r.get("level", 0))
|
|
levels[lvl] = levels.get(lvl, 0) + 1
|
|
return {"total_rules": total, "by_level": levels}
|
|
|
|
def test_logtest(self, log_line, log_format="syslog"):
|
|
"""Test a log line against Wazuh decoders and rules."""
|
|
data = self._api("PUT", "/logtest", data={
|
|
"log_format": log_format,
|
|
"location": "test",
|
|
"event": log_line,
|
|
})
|
|
if not data:
|
|
return {"error": "Logtest failed"}
|
|
result = data.get("data", {})
|
|
return {
|
|
"decoder": result.get("decoder", {}).get("name"),
|
|
"rule_id": result.get("rule", {}).get("id"),
|
|
"rule_description": result.get("rule", {}).get("description"),
|
|
"rule_level": result.get("rule", {}).get("level"),
|
|
"output": result.get("output"),
|
|
}
|
|
|
|
def check_vulnerability_detection(self):
|
|
"""Check if vulnerability detection module is enabled."""
|
|
data = self._api("GET", "/manager/configuration",
|
|
params={"section": "vulnerability-detector"})
|
|
if data:
|
|
config = data.get("data", {}).get("affected_items", [])
|
|
if config:
|
|
enabled = config[0].get("vulnerability-detector", {}).get("enabled", "no")
|
|
if enabled != "yes":
|
|
self.findings.append({
|
|
"severity": "medium", "type": "Vuln Detection Disabled",
|
|
"detail": "Vulnerability detection module is not enabled",
|
|
})
|
|
return {"enabled": enabled == "yes"}
|
|
return {"enabled": False}
|
|
|
|
def generate_report(self):
|
|
agents = self.list_agents()
|
|
summary = self.get_agent_summary()
|
|
alerts = self.query_alerts()
|
|
rules = self.get_rules_summary()
|
|
vuln_det = self.check_vulnerability_detection()
|
|
|
|
report = {
|
|
"report_date": datetime.utcnow().isoformat(),
|
|
"wazuh_url": self.base_url,
|
|
"agent_summary": summary,
|
|
"agents": agents[:50],
|
|
"total_agents": len(agents),
|
|
"recent_critical_alerts": alerts,
|
|
"rules_summary": rules,
|
|
"vulnerability_detection": vuln_det,
|
|
"findings": self.findings,
|
|
"total_findings": len(self.findings),
|
|
}
|
|
out = self.output_dir / "wazuh_detection_report.json"
|
|
with open(out, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(json.dumps(report, indent=2, default=str))
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Manage Wazuh endpoint detection and query alerts"
|
|
)
|
|
parser.add_argument("wazuh_url", help="Wazuh API URL (e.g. https://wazuh:55000)")
|
|
parser.add_argument("--username", default="wazuh-wui", help="API username")
|
|
parser.add_argument("--password", required=True, help="API password")
|
|
parser.add_argument("--output-dir", default="./wazuh_detection")
|
|
args = parser.parse_args()
|
|
|
|
os.makedirs(args.output_dir, exist_ok=True)
|
|
agent = WazuhDetectionAgent(args.wazuh_url, args.username, args.password,
|
|
output_dir=args.output_dir)
|
|
agent.generate_report()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|