What Is Wazuh FIM and Why Should You Care?
File Integrity Monitoring is one of the oldest and most reliable detection primitives in the defensive security toolkit — and Wazuh’s FIM module is one of the most capable open-source implementations available today. At its core, FIM answers a deceptively simple question: did this file change, when did it change, and who is responsible? The operational value of that answer, however, spans ransomware response, web-shell detection, insider threat hunting, and regulatory compliance — all from a single, agent-side module.
In this deep dive I’ll walk through how Wazuh FIM actually works under the hood, how to configure it for production environments, how to write detection rules on top of it, and how to map the resulting alerts to the MITRE ATT&CK framework. Everything here has been validated in lab and production environments running Wazuh 4.7.x on both Linux and Windows endpoints.
How Wazuh FIM Works: Under the Hood
Wazuh FIM operates inside the wazuh-agentd process on each monitored endpoint. On startup, and at every configured scan interval, the agent walks the directory tree you have defined and computes a set of cryptographic hashes and metadata attributes for every file. These baseline snapshots are stored in a local SQLite database (/var/ossec/queue/fim/db/<agent_id>.db). On subsequent scans — or in real-time when inotify/audit/ReadDirectoryChangesW events fire — the agent compares the current state against the stored baseline and emits a syscheck event to the Wazuh manager whenever a discrepancy is found.
The attributes checked by default include MD5, SHA-1, SHA-256, file size, permissions (mode), owner UID/GID, inode number, and modification timestamp. When whodata is enabled, the Linux audit subsystem (auditd) or the Windows Security Event Log is tapped to append the responsible process name, PID, and authenticated user identity to every event — turning a file-change record into a full chain-of-custody entry.
Scheduled Scan vs. Real-Time vs. Whodata
- Scheduled scan (
frequencyparameter): The agent performs a full disk walk every N seconds. Suitable for directories that change infrequently, such as/usr/binor WindowsSystem32. Low overhead, but detection latency equals the scan interval. - Real-time (
realtime="yes"): Uses OS-level filesystem event notifications (inotify on Linux, ReadDirectoryChangesW on Windows). Latency drops to milliseconds. Recommended for web roots, sensitive config directories, and any path targeted by ransomware. - Whodata (
whodata="yes"): Builds on real-time but also captures the responsible user and process via the audit subsystem. Slightly higher CPU overhead due to audit rule injection; worth it for paths holding PII, financial records, or credentials.
Production-Grade FIM Configuration
The following ossec.conf snippet reflects a hardened Linux configuration suitable for a web application server. The design principle is tiered monitoring: apply whodata only where the audit trail justifies the overhead, use real-time everywhere else, and exclude high-churn files that would drown the alert queue in false positives.
<!-- ossec.conf – syscheck block for a Linux web application server -->
<syscheck>
<!-- Global scan fallback: every 12 hours -->
<frequency>43200</frequency>
<!-- Tier 1 – Critical OS binaries and libraries (scheduled + real-time) -->
<directories realtime="yes"
report_changes="yes"
check_all="yes">
/usr/bin,/usr/sbin,/sbin,/bin
</directories>
<!-- Tier 2 – System configuration (scheduled + real-time) -->
<directories realtime="yes"
report_changes="yes"
check_all="yes">
/etc
</directories>
<!-- Tier 3 – Web root: full whodata for chain-of-custody -->
<directories realtime="yes"
report_changes="yes"
whodata="yes"
check_all="yes">
/var/www/html
</directories>
<!-- Tier 4 – SSH and sudo configuration -->
<directories realtime="yes"
report_changes="yes"
whodata="yes">
/etc/ssh,/etc/sudoers.d
</directories>
<!-- Exclusions: high-churn files that generate noise without signal -->
<ignore>/etc/mtab</ignore>
<ignore>/etc/hosts.deny</ignore>
<ignore>/etc/resolv.conf</ignore>
<ignore type="sregex">.log$|.tmp$|.swp$</ignore>
<!-- Alert on newly created files in monitored directories -->
<alert_new_files>yes</alert_new_files>
<!-- Scan on start to establish baseline immediately -->
<scan_on_start>yes</scan_on_start>
</syscheck>
A note on the type="sregex" exclusion: this uses Wazuh’s simple regular expression engine to suppress events for any file whose path ends with .log, .tmp, or .swp. This single line can eliminate hundreds of noisy events per hour on a busy application server without sacrificing coverage of meaningful paths.