docs/ref/modules/rootcheck/architecture.md
This document describes the technical architecture and internal workings of the rootcheck module.
Rootcheck is an agent-side anomaly detection module that performs periodic scans to identify potential security threats. In Wazuh 5.0, rootcheck operates in a stateless mode, meaning all detection happens on the agent and only alerts are sent to the manager without persistent storage.
┌─────────────────────────────────────────┐
│ Wazuh Agent │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Rootcheck Module │ │
│ │ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ Scan Scheduler │ │ │
│ │ │ (frequency-based) │ │ │
│ │ └──────────┬───────────────────┘ │ │
│ │ │ │ │
│ │ ├─────────────────┐ │ │
│ │ ▼ ▼ │ │
│ │ ┌──────────────┐ ┌────────────┐│ │
│ │ │ Detection │ │ Detection ││ │
│ │ │ Engines │ │ Engines ││ │
│ │ └──────────────┘ └────────────┘│ │
│ │ │ │ │ │ │ │ │
│ │ ▼ ▼ ▼ ▼ ▼ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ • Hidden Process Check │ │ │
│ │ │ • Hidden Port Check │ │ │
│ │ │ • File System Anomalies │ │ │
│ │ │ • Device Directory Scan │ │ │
│ │ │ • Promiscuous Mode Check │ │ │
│ │ └───────────┬─────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ Alert Generator │ │ │
│ │ └──────────┬───────────────────┘ │ │
│ └─────────────┼─────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ Agent Communication │ │
│ │ (logcollector) │ │
│ └──────────┬───────────────────────┘ │
└─────────────┼──────────────────────────┘
│
│ (Real-time alerts only)
▼
┌─────────────────────────────────────────┐
│ Wazuh Manager │
│ │
│ ┌────────────────────────────────────┐ │
│ │ analysisd │ │
│ │ (Processes rootcheck alerts) │ │
│ └────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ Rules Engine │ │
│ │ (Matches against rootcheck rules)│ │
│ └────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ Alert Logs & Indexer │ │
│ │ (alerts.log, alerts.json) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Responsibility: Triggers rootcheck scans at configured intervals
Operation:
frequency configuration optionDefault: Every 12 hours (43200 seconds)
Each detection engine runs independently and performs specific checks:
Method:
getsid(pid) - Get session IDgetpgid(pid) - Get process group ID/proc directory entries (Linux)/proc or process lists, trigger alertDetection Logic:
if (pid exists in system call) AND (pid NOT in /proc or ps) {
Alert: Hidden process detected
}
Platform-specific:
/proc filesystemsysctl and kvm interfacesMethod:
bind() system callnetstat outputDetection Logic:
for port in 1..65535 {
if (bind(port) == EADDRINUSE) AND (port NOT in netstat) {
Alert: Hidden port detected
}
}
Optimization:
Checks performed:
Hidden Files Detection:
stat() results with fopen() + read()Directory Entry Count:
opendir() + readdir()stat.st_nlinkUnusual Permissions:
File Attributes:
Scanned directories (Unix):
/bin, /sbin, /usr/bin, /usr/sbin, /dev, /lib, /etc,
/root, /var/log, /var/mail, /var/lib, /var/www,
/usr/lib, /usr/include, /tmp, /boot, /usr/local,
/var/tmp, /sys
Target: /dev directory
Method:
/devDetection Logic:
for file in /dev/* {
if NOT (is_character_device OR is_block_device) {
Alert: Suspicious file in /dev
}
}
Method:
ioctl(SIOCGIFFLAGS)IFF_PROMISC flagifconfig output as secondary checkDetection Logic:
for interface in network_interfaces {
flags = ioctl(interface, SIOCGIFFLAGS)
if (flags & IFF_PROMISC) {
Alert: Interface in promiscuous mode
}
}
Responsibility: Format and send detection results as alerts
Process:
Alert Format:
ossec: output: 'rootcheck' message: <detection_details>
Mechanism: Uses standard Wazuh agent communication channel
Flow:
No Database Persistence (5.0 Change):
No Persistent State (5.0):
Temporary State:
No Persistent State (5.0):
alerts.log and alerts.json/rootcheck API data persistence| Resource | Usage Level | Notes |
|---|---|---|
| CPU | Moderate during scan | Spikes during port scanning and file system checks |
| Memory | Low | Minimal state, streaming processing |
| Disk I/O | Moderate | File system scanning |
| Network | Minimal | Only sends alerts (a few KB per scan typically) |
Typical scan durations (varies by system):
| Check Type | Duration |
|---|---|
| Hidden processes | 1-5 seconds |
| Hidden ports | 30-60 seconds (full port range) |
| File system anomalies | 2-10 minutes (depends on file count) |
| Device directory | <1 second |
| Promiscuous mode | <1 second |
Total: 2-15 minutes for complete scan
Rootcheck is designed to detect common evasion techniques:
Process Hiding:
Port Hiding:
File Hiding:
Kernel-Level Rootkits:
Timing Attacks:
Performance Impact:
1. Scan Trigger (frequency or agent restart)
↓
2. Execute Enabled Checks (parallel)
- check_pids
- check_ports
- check_sys
- check_dev
- check_if
↓
3. Anomaly Detected?
NO → End scan
YES → Continue
↓
4. Format Alert Message
↓
5. Send via logcollector
↓
6. Manager analysisd receives
↓
7. Decode rootcheck message
↓
8. Match against rules (50x series)
↓
9. Generate indexed alert
↓
10. Store in alerts.log, alerts.json, indexer
Rootcheck alerts are processed by rules in the 510-550 range:
| Aspect | Pre-5.0 | 5.0+ |
|---|---|---|
| Manager Database | pm_event table stored all results | No database storage |
| File Signatures | rootkit_files.txt checked | Signature checking removed |
| Trojan Signatures | rootkit_trojans.txt checked | Signature checking removed |
| Policy Checking | system_audit_*.txt processed | Policy checking removed |
| State | Stateful (stored history) | Stateless (alerts only) |
| API Endpoints | Full CRUD operations | Limited (no historical data) |
Advanced tuning via /var/ossec/etc/internal_options.conf:
# rootcheck.sleep
# Number of milliseconds to sleep between PID/port checks
# Lower = faster but higher CPU
# Default: 50
rootcheck.sleep=50
Enable verbose logging:
# Add to internal_options.conf
rootcheck.debug=2
# Restart agent
/var/ossec/bin/wazuh-control restart
Check rootcheck-specific logs:
grep rootcheck /var/ossec/logs/ossec.log