Wazuh on Steroids: AI-Powered Incident Analysis On-Demand

Upgrade Wazuh with an AI-powered active response for on-demand, deep-dive incident analysis.

Wazuh on Steroids: AI-Powered Incident Analysis On-Demand
audio-thumbnail
Podcast AI-Powered Incident Analysis On-Demand
0:00
/226.930958

This article details my enhancement to Wazuh’s active response capabilities, building upon a previously established foundation for automated incident analysis. It introduces an advanced, resource-efficient approach that performs deep log enrichment and AI-powered analysis on-demand whenever an alert is triggered. This “just-in-time” methodology is particularly well-suited for smaller, single-node Wazuh installations, providing the analytical power of a large-scale SOC without the associated infrastructure overhead.

The Challenge: Big SIEM Features for Small Setups

In large Security Operations Centers (SOCs), it is common practice to continuously enrich all incoming logs. Data from sources like firewalls, servers, and applications are forwarded to a complex pipeline, often involving tools like Logstash or Graylog. Here, they are parsed, normalized, and enriched with threat intelligence, geolocation data, and other contextual information before being stored in a massive database like Elasticsearch. While incredibly powerful, this approach requires significant computational resources and storage, making it impractical for smaller environments or home labs.

The central question is: How can the deep analytical insight of a full-scale enrichment pipeline be achieved in a more resource-friendly manner?

A New Approach: Just-in-Time Threat Intelligence

Instead of enriching every single log message, the strategy is shifted to perform this process only when it truly matters: after Wazuh has already identified a potential threat and generated an alert. This on-demand approach dramatically reduces the constant processing load and cost. It builds upon the concepts outlined in the article Automated Incident Analysis with Wazuh, but refines the process for maximum efficiency.

When a high-priority alert is triggered, an active response script is executed. This script takes the alert context, performs a comprehensive investigation of the suspicious indicators (like a source IP address), gathers related historical logs, and then packages all this information to be analyzed by a generative AI.

The Components of my Automated Analyst

This solution integrates several key components into a seamless workflow:

  1. Wazuh: Acts as the Security Information and Event Management (SIEM) system, detecting threats and triggering the workflow.
  2. Bash Script: The core orchestrator. It receives the alert, performs the investigation, communicates with the AI, and sends the final summary.
  3. Threat Intelligence APIs: A collection of external services (AbuseIPDB, VirusTotal, Shodan, etc.) are queried in real-time to build a reputation profile of the attacker.
  4. Generative AI (ollama with qwen-coder): Functions as the “SOC Analyst.” It receives a structured brief with all collected data and is tasked with generating a human-readable incident summary.
  5. Ntfy: A simple, open-source push notification service used to deliver the final, formatted summary to a mobile device or desktop.

With these core components, no data leaves the network except for the queries sent to the Threat Intelligence APIs.

The Orchestrator: A Deep Dive into the Active Response Script

Based on the article Automated Incident Analysis with Wazuh, the entire logic is encapsulated within a single Bash script. This script is designed to be self-contained and is triggered directly by Wazuh. Let’s break down the updates to the key functions.

Step 1: Receiving the Alert

Wazuh passes the full alert data as a JSON object to the script via standard input (stdin). The script captures this data securely to prevent it from hanging.

# [...]
# Read stdin directly into a variable with a 2-second timeout
# to prevent the script from getting stuck.
ALERT_JSON=$(timeout 2s cat)

# Check if data was successfully read
if [ -z "${ALERT_JSON}" ]; then
    echo "$(date) ntfy.sh: [ERROR] ALERT_JSON is empty after read attempt." >> ${LOG_FILE} 2>&1
    exit 1
fi
# [...]

Step 2: The Investigator - wer_issn

Once the source IP address is extracted from the alert, a comprehensive investigation function, humorously named wer_issn (a colloquial German “Who is this?”), is called. This function is our trusty digital bloodhound, querying a multitude of sources to build a complete picture of the IP in question:

  • GeoIP & Network Info: ipinfo.io for location, ASN, and organization data.
  • WHOIS: For network block ownership and contact details.
  • Reputation & Abuse:
    • AbuseIPDB: Provides a confidence score based on community reports.
    • VirusTotal: Checks against dozens of antivirus engines and blocklist services.
    • GreyNoise: Determines if the IP is part of the general internet “noise” or a known malicious scanner.
  • Security Posture:
    • Shodan: Reveals open ports and known vulnerabilities.
    • TOR Check: Identifies if the IP is a known TOR exit node.
  • DNS Blacklists (DNSBL): Checks against common spam and attack blocklists like Spamhaus.

Finally, this function calculates a risk score based on the collected negative indicators and provides a preliminary assessment.

Step 3: Briefing the AI Analyst

This is where the core process takes place. All the collected information—the original Wazuh alert, the detailed IP profile from wer_issn, historical logs related to the attacker’s IP, and crucial network topology context—is compiled into a detailed prompt for the ollama AI.

Providing network context is vital for a high-quality analysis. The AI is informed about the local network structure (e.g., DMZ, Server LAN, Client LAN) so it can correctly interpret the attack’s target and potential impact.

# M. Meister
# [...]
# alternative for https://blog.meister-security.de/script-time-domain-routing/ or ipam:
NETWORK_CONTEXT=$(cat << 'EOF'
The firewall `mastergate` always has the .254 in the following networks:
DMZ:            192.168.D.0/24
Server-Segment: 192.168.S.0/24
Client-Segment: 192.168.C.0/24
...
EOF
)

# [...]

PROMPT=$(cat <<EOF
You are an experienced IT security analyst. Your task is to generate a concise incident report in Markdown from the following data.

### INPUT DATA ###

**1. Primary Alert (Trigger):**
${ALERT_JSON}

**2. Additional Information:**
- Attacker's IP Address: ${SRCIP:-Not available}
- Information about the attacker: ${SRCIPINFO}
- Host that reported the attack: ${AGENT_NAME}

**3. Known past activities of the IP address ${SRCIP}:**
${CONTEXT_LOGS}

**4. Infrastructure Context (Network Topology):**
(Use this to map hosts to network zones — DMZ, Server Net, Client Net.)
${NETWORK_CONTEXT}


## YOUR TASK
Create an incident report containing the following sections:

### 1. Title  
Create a short, descriptive title that summarizes the event (e.g., *“Login after brute-force attack”*).

### 2. Overview  
Summarize what happened, when it occurred, and how it was detected.

### 3. Involved Components  
Identify all involved hosts, their roles, and networks (based on provided context).

### 4. Incident Details  
From the logs, reconstruct the sequence of events:  
- Connection attempts or alerts from firewall or IDS.  
- Detected rule matches or signature names.  
- Log sources that contributed evidence.  
- Key timestamps (first, last, frequency of activity).  
- Whether the activity escalated (e.g., successful login, privilege change, file modification).

### 5. Attacker Profile (from logs)  
- Source IP, geo-location, and reputation info.  
- Repeated attempts, scanning behavior, or rule matches across multiple hosts.  
- Common ports, protocols, or patterns seen in IDS or firewall logs.

### 6. Target System Details  
- Hostname and IP.  
- Services or ports targeted (from IDS/firewall logs).  
- Observed local effects (e.g., failed logins, new processes, file modifications, configuration changes).

### 7. Indicators of Compromise (IoCs)  
Extract from logs where available:  
- Source/Destination IPs, domains.  
- File paths, process names, command lines.  
- Usernames involved in authentication events.  
- Matched rule IDs or signatures.

### 8. Risk Assessment  
Assess the severity based on:  
- Attack type (recon, brute force, exploit, privilege escalation).  
- Whether compromise indicators were detected locally.  
- Exposure level of the target (DMZ vs internal).  
Use one of: **Critical**, **High**, **Medium**, **Low**.

### 9. Recommended Actions  
Based only on log evidence, suggest concrete steps, such as:  
- Blocking IPs or subnets on firewall.  
- Investigating affected hosts (check processes, users, modified files).  
- Updating detection rules or patching vulnerable services.  
- Enhancing log collection or correlation.

### OUTPUT FORMAT (TO BE STRICTLY FOLLOWED) ###
- **Start IMMEDIATELY with the title:** Your response must start directly with the Markdown heading `# ...` without any introductory text.
- **Only the report:** Output only the Markdown report.
- **Be extremely brief (max. 3500 characters):** Aggressively shorten all sections. The output is for a push notification.
- **No outer code block:** The entire output must not be enclosed in \`\`\`.
EOF
)

# ... API call to ollama follows ...

Step 4: Delivering the summary via Ntfy

The AI’s response, which is a fully formatted Markdown summary, is then sent as a push notification using curl to a specified Ntfy topic. The priority and icon of the notification are dynamically set based on the original Wazuh alert level.

Integration with Wazuh: The Configuration

To make this script operational, it must be registered within Wazuh’s main configuration file, /var/ossec/etc/ossec.conf, on the Wazuh manager.

  1. Place the Script: The script (e.g., ai-analyzer.sh) must be placed in the active response directory, typically /var/ossec/active-response/bin/, and made executable (chmod +x ai-analyzer.sh).
  2. Define the Command: A <command> block defines the script and tells Wazuh to pass the full alert in JSON format.
  3. Create the Active Response: An <active-response> block links the command to specific rule groups or alert levels. This example triggers the script for any rule in the sshd or authentication_failed groups with a level of 10 or higher.

Here is a complete configuration example to be added to ossec.conf:

  <!-- Custom AI Active Response -->
  <command>
    <name>ai-analyzer</name>
    <executable>ai-analyzer.sh</executable>
    <expect>alert_json</expect>
    <timeout_allowed>yes</timeout_allowed>
  </command>

  <active-response>
    <command>ai-analyzer</command>
    <location>server</location>
    <level>10</level>
  </active-response>

After adding this configuration, the Wazuh manager must be restarted for the changes to take effect.

The Final Product: An AI-Crafted Incident Summary

The outcome is a concise, context-aware incident summary delivered as a push notification. It turns a raw alert into actionable intelligence, including risk evaluation and remediation guidance. The AI produces only a short summary, optimized to fit within ntfy’s 3,500-character limit. The following is the latest report, that was sent to me during testing.

Incident Report — Possible Brute-Force Attack

Possible Brute-Force Attack

Observed: Oct 22 2025 — 16:53 to 17:22

Overview

Multiple block events from IP 185.55.243.23 were observed on the pfSense firewall mastergate.meister.world. An ongoing brute‑force attempt on internal systems is suspected.

Involved Components

  • mastergate.meister.world (Wazuh agent) — pfSense firewall (internal IP: 192.168.188.254)
  • 185.55.243.23 — potential attacker (Internet)
  • 192.168.111.81 (webdocker) — web server in DMZ (192.168.111.0/24)

Incident Details

The firewall blocked multiple connection attempts from 185.55.243.23 to various internal ports (8080, 8090, 33063).

Oct 22 17:22:34 mastergate.meister.world filterlog[19145]: 130,,,3555037a522d9012ab7e1c845d58ede6,vtnet1,match,block,in,4,0x0,,55,14612,0,DF,6,tcp,60,185.55.243.23,192.168.188.254,33063,8080,0,S,1236333521,,64240,,mss;sackOK;TS;nop;wscale
        

Prior to this, the DMZ webserver webdocker (192.168.111.81) logged 444 errors and an Active Response block was triggered.

Attacker Profile

The IP 185.55.243.23 is registered to Layer7 Networks GmbH, Frankfurt, Germany. AbuseIPDB score: 5 (2 reports). VirusTotal and multiple blacklists report issues for this IP.

Target System

The pfSense firewall mastergate.meister.world (192.168.188.254) was targeted directly. The volume of blocked attempts suggests brute-force attempts against internal services (Server Net: 192.168.110.0/24, Client Net: 192.168.101.0/24).

Risk Assessment

Medium. The source IP is known malicious and active brute-force attempts were observed. Firewall blocking reduces exposure but immediate follow-up is required.

Recommended Actions

  • Block 185.55.243.23 on the external firewall (192.109.79.235).
  • Review firewall rules and close unnecessary open ports.
  • Inspect logs of affected internal systems (Server & Client networks) for suspicious activity.
  • Enable/strengthen brute‑force protections (e.g., Fail2Ban) on targeted services.
  • Enable multi‑factor authentication for critical accounts and services.
Generated from Wazuh host, firewall, and IDS logs — evidence-only summary.

This is only the push notification. In my setup, the AI also generates a full report in LaTeX format, which is compiled with pdflatex and sent via email. That way, I have a polished, management-ready document on hand whenever it’s needed.

Conclusion

This on-demand analysis and enrichment approach offers a powerful yet lightweight way to enhance Wazuh alerts. By combining external threat intelligence with generative AI analytics when needed, it delivers deep incident insights without requiring a costly, always-on data pipeline. Since attacker IP reputation checks only need to be performed once using a free plan, it’s an ideal upgrade for small to medium Wazuh deployments—essentially providing a “SOC analyst in a box.”