security operations

Implementing Endpoint Detection with Wazuh

Deploy and configure Wazuh SIEM/XDR for endpoint detection including agent management, custom decoder and rule XML creation, alert querying via the Wazuh REST API, and automated response actions.

custom-rulesendpoint-detectionincident-responsesiemwazuhxdr
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

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 requests library
  • 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.

Source materials

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

Scripts 1

agent.py7.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/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()
Keep exploring