npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
Overview
Wazuh is an open-source SIEM and XDR platform for endpoint monitoring, threat detection, and compliance. This skill covers managing agents via the Wazuh REST API, creating custom decoders and rules in XML for organization-specific detections, querying alerts, and testing rule logic using the logtest endpoint.
When to Use
- When deploying or configuring implementing endpoint detection with wazuh capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- Wazuh Manager 4.x deployed with API enabled
- Python 3.9+ with
requestslibrary - API credentials (username/password for JWT authentication)
- Understanding of Wazuh decoder and rule XML syntax
Steps
Step 1: Authenticate to Wazuh API
Obtain JWT token via POST to /security/user/authenticate.
Step 2: List and Monitor Agents
Query agent status, versions, and last keep-alive via /agents endpoint.
Step 3: Query Security Alerts
Search alerts by rule ID, severity, agent, or time range.
Step 4: Test Custom Rules with Logtest
Use the /logtest endpoint to validate decoder and rule logic against sample log lines.
Expected Output
JSON report with agent inventory, alert statistics, rule coverage, and logtest validation results.
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.0 KB
API Reference: Implementing Endpoint Detection with Wazuh
Wazuh REST API Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
| /security/user/authenticate | POST | Get JWT token (Basic Auth) |
| /agents | GET | List agents with status |
| /agents/summary/status | GET | Agent status summary |
| /alerts | GET | Query security alerts |
| /rules | GET | List detection rules |
| /logtest | PUT | Test log against decoders/rules |
| /manager/configuration | GET | Manager configuration |
| /agents/{id}/restart | PUT | Restart specific agent |
Authentication
import requests
from requests.auth import HTTPBasicAuth
resp = requests.post(
"https://wazuh:55000/security/user/authenticate",
auth=HTTPBasicAuth("wazuh-wui", "password"),
verify=False,
)
token = resp.json()["data"]["token"]
headers = {"Authorization": f"Bearer {token}"}Custom Rule XML Syntax
<group name="custom_rules,">
<rule id="100001" level="12">
<if_sid>5716</if_sid>
<srcip>!192.168.1.0/24</srcip>
<description>SSH login from external IP</description>
<mitre><id>T1078</id></mitre>
</rule>
</group>Location: /var/ossec/etc/rules/local_rules.xml
Custom Decoder XML
<decoder name="custom_app">
<program_name>myapp</program_name>
<regex>^(\S+) (\S+) (\S+)</regex>
<order>srcip,user,action</order>
</decoder>Location: /var/ossec/etc/decoders/local_decoder.xml
Alert Query Parameters
| Parameter | Example | Description |
|---|---|---|
| limit | 20 | Max results |
| sort | -timestamp | Sort descending |
| q | rule.level>=10 | Filter by level |
| search | brute force | Text search |
| select | rule.id,agent.name | Field selection |
References
- Wazuh API Docs: https://documentation.wazuh.com/current/user-manual/api/
- Wazuh Rules Syntax: https://documentation.wazuh.com/current/user-manual/ruleset/ruleset-xml-syntax/rules.html
- Wazuh Custom Rules: https://documentation.wazuh.com/current/user-manual/ruleset/rules/custom.html
Scripts 1
agent.py7.4 KB
#!/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()