Automating Real-Time File Integrity Monitoring (FIM) and Active Response with Wazuh SIEM
Relying on scheduled file integrity scans once a night via cron or passive log collection leaves your infrastructure exposed for hours: if an attacker drops a webshell at ten in the morning, they have the entire day to exfiltrate database records before any alert triggers.
In high-throughput sectors like Fintech Startups (Neobanks) and mission-critical operations like Astrotourism & Stratospheric Travel, an automated exploit takes under ninety seconds from file drop to kernel privilege escalation.
At Webxtek Studio, we connect Wazuh SIEM directly to the Linux kernel audit subsystem (auditd) with whodata="yes". This detects unauthorized script creation in milliseconds, identifies the exact binary and user responsible, and triggers automated Active Response playbooks that quarantine payloads and block attacking IPs in nftables before the webshell can execute.
This active detection and response posture directly operationalizes the perimeter lockdown detailed in our CISA, NSA & FBI Emergency Playbook: PHP, Node.js & Port Hardening.
Below is the step-by-step implementation guide to configure real-time FIM and active response on your production Linux nodes.
1. From Midnight Checklists to Kernel auditd: How Wazuh FIM with whodata Works
To detect and neutralize webshells and unauthorized binary changes in milliseconds on Linux, you must configure the Wazuh syscheck engine with whodata="yes" backed by the kernel auditd service, write surgical detection rules for script creation in web roots, and wire an Active Response playbook that isolates the payload and blocks the attacking IP in nftables.
To understand why legacy file integrity tools fail against modern adversaries, you must differentiate the three operational modes of the syscheck engine, as documented in the official Wazuh File Integrity Monitoring documentation:
- Scheduled Scan Mode: The agent traverses the filesystem every 12 hours computing SHA-256 checksums. If an attacker injects a webshell at 10:05, executes command payloads, and deletes the shell at 10:08, the 22:00 scan detects absolutely nothing!
- Real-Time Mode (
realtime="yes"viainotify): The agent listens forIN_MODIFY,IN_CREATE, andIN_DELETEevents through the Linux kernelinotifyAPI. Alerts trigger in near-real time, but there is a major forensic blind spot: Linuxinotifyreports which file was modified (/var/www/app/public/uploads/shell.php), but cannot identify which user or system process executed the write operation. - Who-Data Mode (
whodata="yes"via Kernelauditd): This is the hardened standard we enforce in production. Instead of standardinotify, Wazuh injects dynamic rules into the Linux Audit (auditd) subsystem at the system call boundary (sys_openat,sys_write,sys_unlink,sys_chmod).
Real-Time Forensic Flow: Wazuh FIM (whodata="yes") + Active Response
1. Intrusion:
A web exploit causes php-fpm8.4 to write '/var/www/html/uploads/backdoor.php'.
2. Kernel Interception:
The Linux Audit subsystem (auditd) captures the write() syscall at the VFS layer.
3. Who-Data Tracing:
The Wazuh Agent receives irrefutable metadata directly from the auditd socket:
- File: /var/www/html/uploads/backdoor.php (New SHA-256 calculated)
- Effective User (euid): www-data (UID 33) | Audit UID (auid): 4294967295
- Responsible Process: /usr/sbin/php-fpm8.4 (PID 14820 | PPID 1102)
4. SIEM Decision Engine (50ms):
Wazuh Manager evaluates the critical alert rule (Rule 100550: PHP script created in uploads directory).
5. Automated Active Response:
The agent executes the 'webxtek-quarantine.sh' playbook:
- Atomically moves backdoor.php to /var/ossec/quarantine/ with 0000 permissions (neutralizing execution).
- Blocks the attacking IP in the Linux kernel nftables ruleset.
Notice the forensic power of the whodata layer: if a human operator connects over SSH as pedro (UID 1002), runs sudo su - to elevate to root (UID 0), and secretly edits a line in /etc/ssh/sshd_config, Wazuh records:
user_name:root(the effective user executing the write)audit_uid:pedro (1002)(the immutable login identity that opened the initial shell session, preserved by kernel auditd regardless of privilege escalation)process_name:/usr/bin/nano- And, thanks to
report_changes="yes", the exact diff of the line modified in the file!
2. Production Configuration: Hardening auditd and /var/ossec/etc/ossec.conf
Let us configure your Debian 12 or Ubuntu 24.04 LTS host to activate whodata auditing across critical operating system paths and application directories, while safeguarding configuration secrets using <nodiff>.
Step 1: Install and Tune the auditd Daemon on Linux
By default, minimal cloud images lack auditd or operate with an undersized kernel backlog buffer that drops events during I/O surges. Install and tune auditd on your node:
# 1. Install Linux Audit subsystem and parsing utilities
sudo apt-get update && sudo apt-get install -y auditd audispd-plugins jq
# 2. Expand kernel queue backlog (-b 8192) to prevent event loss during peak I/O
cat << 'EOF' | sudo tee /etc/audit/rules.d/10-wazuh-buffer.rules
-b 8192
-f 1
EOF
sudo augenrules --load
sudo systemctl enable --now auditd
Step 2: Configure the <syscheck> Block in the Wazuh Agent (/var/ossec/etc/ossec.conf)
Edit /var/ossec/etc/ossec.conf on your monitored host and replace the <syscheck> section with this configuration, aligned with production guidelines from documentation.wazuh.com on FIM:
<!-- ==========================================================================
/var/ossec/etc/ossec.conf (<syscheck> block on Linux nodes)
Real-Time Monitoring + Who-Data Tracking (auditd) + Secret Suppression (nodiff)
========================================================================== -->
<syscheck>
<disabled>no</disabled>
<!-- Baseline reconciliation scan every 6 hours; whodata evaluates immediately -->
<frequency>21600</frequency>
<scan_on_start>yes</scan_on_start>
<alert_new_files>yes</alert_new_files>
<auto_ignore frequency="10" timeframe="3600">no</auto_ignore>
<!-- 1. Critical System Binaries: Detect rootkit implants and trojans with whodata -->
<directories check_all="yes" whodata="yes">/bin,/sbin,/usr/bin,/usr/sbin,/usr/local/bin</directories>
<!-- 2. System Configurations (/etc): Capture author identity and exact modified lines -->
<directories check_all="yes" whodata="yes" report_changes="yes">/etc/ssh,/etc/pam.d,/etc/sudoers.d,/etc/nginx,/etc/php,/etc/cron.d,/etc/systemd/system</directories>
<directories check_all="yes" whodata="yes" report_changes="yes">/etc/passwd,/etc/group,/etc/hosts,/etc/resolv.conf,/etc/nftables.conf</directories>
<!-- 3. Web Application Codebases: Monitor unauthorized script injection -->
<directories check_all="yes" whodata="yes" report_changes="yes" restrict="\.php$|\.phtml$|\.phar$|\.py$|\.pth$|\.sh$|\.mjs$|\.js$|\.htaccess$">/var/www</directories>
<!-- 4. User Upload Directories: Code execution must NEVER occur here; monitor in full whodata -->
<directories check_all="yes" whodata="yes">/var/www/app_production/storage/app/public,/var/www/app_production/public/uploads</directories>
<!-- 5. Performance Exclusions: Ignore ephemeral caches, logs, and git objects -->
<ignore>/var/www/app_production/storage/framework/cache</ignore>
<ignore>/var/www/app_production/storage/framework/views</ignore>
<ignore>/var/www/app_production/storage/logs</ignore>
<ignore type="sregex">\.log$|\.swp$|\.tmp$|/node_modules/|/\.git/objects/</ignore>
<!-- 6. SECRETS SUPPRESSION (<nodiff>): Compute SHA-256 changes, but NEVER send passwords to SIEM! -->
<nodiff>/etc/shadow</nodiff>
<nodiff>/etc/gshadow</nodiff>
<nodiff type="sregex">\.env$|wp-config\.php$|\.pem$|\.key$|id_ed25519$|users\.acl$</nodiff>
<!-- Disk safety controls for diff storage -->
<disk_quota enabled="yes">1G</disk_quota>
<file_size enabled="yes">50M</file_size>
</syscheck>
Restart the Wazuh agent and verify that the auditd rules (wazuh_fim) have been registered with the kernel:
sudo systemctl restart wazuh-agent
# Confirm Wazuh registered whodata watches directly with the Linux audit subsystem
sudo auditctl -l | grep wazuh_fim
3. Detection Rules and Active Response Playbook: Automated Webshell Quarantine
Detecting that a shell.php file was created inside /public/uploads/ at three in the morning is helpful, but if no operator is awake to review alerts, an attacker has hours to pivot across internal systems.
This detection pattern is specifically designed to stop multi-stage injection attacks like those analyzed in our playbook on cPanel, Plesk, CyberPanel & HestiaCP: PHP2Shell Mitigation & FPM Hardening.
We configure Active Response following the official Wazuh Active Response architecture, allowing the server itself to neutralize the file within 100 milliseconds.
Step 1: Create the High-Severity Rule in Wazuh Manager (/var/ossec/etc/rules/local_rules.xml)
On your centralized Wazuh Manager node, add this custom rule definition that raises an alert to Level 14 (Critical Emergency) whenever an executable .php, .phtml, .py, or .sh file is written inside public upload directories, or whenever modified by php-fpm / www-data:
<!-- File on Wazuh Manager: /var/ossec/etc/rules/local_rules.xml -->
<group name="syscheck,webxtek_fim_defense,">
<!-- Rule 100550: Detect PHP/script creation in upload folders or by www-data user -->
<rule id="100550" level="14">
<if_sid>554,550</if_sid>
<field name="file" type="pcre2">(?i)/uploads/.*\.(php\d?|phtml|phar|py|sh|pl|cgi|pth)$|(?i)/storage/.*\.(php\d?|phtml|phar|pth)$</field>
<description>[CRITICAL FIM] Webshell or executable script injected in data path: $(file) by process $(audit.process.name) (UID:$(audit.euid.name)).</description>
<mitre>
<id>T1505.003</id>
</mitre>
<group>webshell_detected,pci_dss_11.5,gdpr_IV_35.7.d,</group>
</rule>
<!-- Rule 100551: Detect if php-fpm or node wrote a script to web root outside deployment window -->
<rule id="100551" level="13">
<if_sid>554</if_sid>
<field name="audit.process.name" type="pcre2">php-fpm|lsphp|apache2|nginx|node</field>
<field name="file" type="pcre2">(?i)\.(php\d?|phtml|phar|pth|py|sh)$</field>
<description>[RCE ALERT FIM] Web runtime ($(audit.process.name)) wrote a new executable script: $(file). Potential RCE / PHP2Shell exploit!</description>
<mitre>
<id>T1190</id>
<id>T1505.003</id>
</mitre>
</rule>
</group>
Step 2: The Quarantine Active Response Script on the Linux Node
On the monitored Linux node running wazuh-agent, create the executable /var/ossec/active-response/bin/webxtek-quarantine-file.sh. When rule 100550 or 100551 fires, this script reads the alert JSON via stdin, extracts the file path, atomically relocates it to an isolated directory (/var/ossec/quarantine), revokes all permissions (chmod 0000), and records forensic telemetry:
#!/usr/bin/env bash
# ============================================================================
# /var/ossec/active-response/bin/webxtek-quarantine-file.sh
# Wazuh Active Response Playbook: Instant Webshell Containment
# ============================================================================
set -uo pipefail
QUARANTINE_DIR="/var/ossec/quarantine"
LOG_FILE="/var/ossec/logs/active-responses.log"
mkdir -p "$QUARANTINE_DIR"
chmod 0700 "$QUARANTINE_DIR"
# 1. Read JSON payload passed by Wazuh Agent over STDIN
read -r INPUT_JSON
COMMAND=$(echo "$INPUT_JSON" | jq -r '.command // empty')
FILENAME=$(echo "$INPUT_JSON" | jq -r '.parameters.alert.syscheck.path // empty')
RULE_ID=$(echo "$INPUT_JSON" | jq -r '.parameters.alert.rule.id // empty')
PROC_NAME=$(echo "$INPUT_JSON" | jq -r '.parameters.alert.syscheck.audit.process.name // "unknown"')
PROC_PID=$(echo "$INPUT_JSON" | jq -r '.parameters.alert.syscheck.audit.process.id // "0"')
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Execute only on 'add' action and ensure path targets /var/www
if [[ "$COMMAND" == "add" && -n "$FILENAME" && "$FILENAME" == /var/www/* && -f "$FILENAME" ]]; then
SAFE_BASENAME=$(basename "$FILENAME")
QUARANTINE_TARGET="${QUARANTINE_DIR}/${TIMESTAMP}_rule${RULE_ID}_${SAFE_BASENAME}.malicious"
# 2. Atomically move webshell out of web root and zero all execution bits (0000)
mv -f "$FILENAME" "$QUARANTINE_TARGET"
chmod 0000 "$QUARANTINE_TARGET"
chown root:root "$QUARANTINE_TARGET"
echo "${TIMESTAMP} [WEBXTEK_ACTIVE_RESPONSE] SUCCESS: Suspect payload '${FILENAME}' created by '${PROC_NAME}' (PID ${PROC_PID}) quarantined at '${QUARANTINE_TARGET}' (Rule ${RULE_ID})." >> "$LOG_FILE"
else
echo "${TIMESTAMP} [WEBXTEK_ACTIVE_RESPONSE] Ignored or file already purged: '${FILENAME}'." >> "$LOG_FILE"
fi
exit 0
Set the strict ownership and executable permissions required by Wazuh:
sudo chown root:wazuh /var/ossec/active-response/bin/webxtek-quarantine-file.sh
sudo chmod 0750 /var/ossec/active-response/bin/webxtek-quarantine-file.sh
Finally, register the command and active response trigger in /var/ossec/etc/ossec.conf on the Wazuh Manager:
<!-- Register in /var/ossec/etc/ossec.conf on Wazuh Manager -->
<command>
<name>webxtek-quarantine-file</name>
<executable>webxtek-quarantine-file.sh</executable>
<timeout_allowed>no</timeout_allowed>
</command>
<active-response>
<disabled>no</disabled>
<command>webxtek-quarantine-file</command>
<location>local</location>
<rules_id>100550,100551</rules_id>
</active-response>
Consider how this layered defense operates under real exploit conditions: even if an adversary discovers an unpatched file upload flaw in a third-party plugin and successfully writes exploit.php into /uploads/, the moment the file touches disk, auditd notifies Wazuh, rule 100550 triggers, and webxtek-quarantine-file.sh removes the file from the public directory before the attacker can dispatch an HTTP GET /uploads/exploit.php request to execute the webshell!
4. Technical Comparison: Passive Logs vs. Wazuh FIM (whodata + Active Response)
The table below contrasts standard periodic monitoring with the active defense architecture deployed across infrastructure managed by Webxtek Studio:
| Security Dimension / Response | Traditional Monitoring (Cron / Basic inotify) | Hardened Webxtek Standard (Wazuh whodata + Active Response) | Real-World Production Impact |
|---|---|---|---|
| Mean Time to Detection (MTTD) | 12 to 24 hours (nightly scan) | < 50 milliseconds (direct kernel auditd event) | Catches intrusions at the exact moment of disk write |
| Attribution (Who-Data) | Unknown (detects file modification, not the actor) | Full Attribution (auid, euid, pid, and exact binary path) |
Immediately reveals whether action was interactive SSH or a web runtime |
| Change Visibility (Diff) | Flags changed SHA-256 hash only | Displays exact line of modified source code (report_changes) |
Speeds up incident triage by 90% |
| Secrets Protection | Risk of leaking .env or passwords to log indexer |
Cryptographically suppressed at source via <nodiff> |
Full compliance with GDPR, PCI-DSS v4.0, and ISO 27001 |
| Mean Time to Remediation (MTTR) | Hours (waiting for on-call engineer intervention) | Automated (< 200 ms) via file quarantine and IP drop | Neutralizes webshell before first execution request |
When leading demanding operations in Fintech Startups (Neobanks) or mission-critical platforms in Astrotourism & Stratospheric Travel, where custom Web Apps process high-value client transactions and high-budget campaigns produced through Video Production for Digital Impact generate massive bursts of global traffic, anchoring your stack on our Managed Hosting for Websites and Apps with active Wazuh enforcement gives you the assurance of an automated sentinel guarding every system call 24 hours a day.
5. Five-Step Production Readiness Checklist
Before signing off on your Wazuh SIEM deployment, verify these five operational controls from your Linux terminal:
- Validate the whodata Trigger with a Harmless Canary: Create a dummy test file under the web user identity (
sudo -u www-data touch /var/www/app_production/public/uploads/canary_test.php) and inspect/var/ossec/logs/active-responses.logto verify that the file was relocated to/var/ossec/quarantine/in under a second and registered in the Wazuh console withaudit.euid.name: www-data. - Prevent Automated Lockout (IP Whitelisting): In the
<global>section of/var/ossec/etc/ossec.confon the Wazuh Manager, explicitly define inside<white_list>tags your corporate egress IPs, WireGuard VPN gateways, CDN edge nodes (Cloudflare), and resolver IPs (1.1.1.1,8.8.8.8) to ensure an attacker cannot spoof packets to trigger firewall blocks against your own team. - Audit the
<nodiff>Configuration: Ensure in compliance with documentation.wazuh.com that no configuration files storing private keys, certificates, or database credentials (.env,wp-config.php,/etc/shadow) are forwarding plaintext diff payloads to the OpenSearch indexer. - Mute Deploy Paths During Release Pipelines: To prevent Rule 100551 from triggering false positives during automated CI/CD runs, configure deployment tasks to execute under a dedicated service user (
deployer) and restrict the automated quarantine rule to writes originated by web server daemons (php-fpm,nginx,apache2). - Enforce Agent Immutability and Heartbeat Telemetry: Monitor
/var/ossec/etc/ossec.confand configure thewazuh-agentsystemd service withRestart=alwaysto ensure that any unauthorized attempt to disable the monitoring daemon triggers an immediate alert and heartbeat loss event (agent disconnected) on the central cluster. Beyond host-level detection with Wazuh, pre-deployment code auditing can be automated through dedicated security agents, as detailed in our Autonomous Security Audit Agents: Dual Hunter-Verifier Architecture.
Modern cybersecurity is won or lost in the split second between an attacker touching your disk and your defense responding. At Webxtek Studio, we combine Linux systems engineering with automated active defense to safeguard enterprise operations. Through our specialized solutions in Managed Hosting for Websites and Apps, bespoke development of Web Apps, and visual digital storytelling via Video Production for Digital Impact, we ensure your digital operations scale with uncompromising resilience, forensic clarity, and peak performance.
[+] [ INDEX_DIRECTORY ] 17 topics ▼
- 1. From Midnight Checklists to Kernel auditd: How Wazuh FIM with whodata Works
- 2. Production Configuration: Hardening auditd and /var/ossec/etc/ossec.conf
- Step 1: Install and Tune the auditd Daemon on Linux
- Step 2: Configure the <syscheck> Block in the Wazuh Agent (/var/ossec/etc/ossec.conf)
- 3. Detection Rules and Active Response Playbook: Automated Webshell Quarantine
- Step 1: Create the High-Severity Rule in Wazuh Manager (/var/ossec/etc/rules/local_rules.xml)
- Step 2: The Quarantine Active Response Script on the Linux Node
- 4. Technical Comparison: Passive Logs vs. Wazuh FIM (whodata + Active Response)
- 5. Five-Step Production Readiness Checklist
- Author
- Frequently Asked Questions
- What is the technical difference between realtime='yes' (inotify) and whodata='yes' (auditd) in Wazuh File Integrity Monitoring (FIM)?
- How does the auditd Audit UID (auid) attribute prevent an attacker from hiding their identity after privilege escalation to root?
- How does the Wazuh Active Response module neutralize a webshell and block the attacker in milliseconds?
- What security precautions must you take with the report_changes='yes' directive in Wazuh to avoid leaking secrets into SIEM logs?
- Related Nodes
- Path Sequence
Frequently Asked Questions
What is the technical difference between realtime='yes' (inotify) and whodata='yes' (auditd) in Wazuh File Integrity Monitoring (FIM)?
The realtime='yes' mode uses the Linux kernel inotify API to instantly detect when a file is created or modified, but inotify does not record which user or process performed the modification. In contrast, whodata='yes' attaches Wazuh directly to the Linux Audit subsystem (auditd), capturing in real time the Audit UID (auid), effective user (euid), PID, executable binary name, and parent process that accessed the file.
How does the auditd Audit UID (auid) attribute prevent an attacker from hiding their identity after privilege escalation to root?
When a user logs in via SSH as 'external_dev' (UID 1005) and runs 'sudo su -' to become 'root' (UID 0), standard tools only report 'root'. However, the Linux kernel immutably preserves the original login user in the auid=1005 field. With whodata='yes' in Wazuh, you determine the exact initial account that originated the file modification, even across multiple sudo jumps.
How does the Wazuh Active Response module neutralize a webshell and block the attacker in milliseconds?
When the Wazuh Manager analysis engine receives a FIM event for a suspicious .php file creation or web exploitation attempt matching a critical severity rule, it issues a signed command back to the Linux agent. The agent immediately executes a local script in /var/ossec/active-response/bin/ that moves the malicious file into an isolated quarantine folder with zero execution permissions and drops the source IP in the nftables firewall.
What security precautions must you take with the report_changes='yes' directive in Wazuh to avoid leaking secrets into SIEM logs?
The report_changes='yes' directive maintains a local copy of monitored text files to calculate and forward the exact line diff to the Wazuh dashboard. To prevent TLS private keys, .env files, or /etc/shadow from being indexed in plaintext in your SIEM, you must explicitly declare these sensitive files inside
[ RELATED_NODES ]
> START_PROJECT
Need a website that earns trust, ranks in search, and gives your business a stronger digital presence? Start the conversation here.