The Linux Audit daemon (auditd) records file accesses, process executions, and privilege changes at the kernel level — events that application-level logging never captures. For WordPress servers, auditing writes to wp-config.php, executions of PHP in the uploads directory, and su/sudo events gives you a tamper-evident log trail that survives even if the attacker deletes application logs.
Problem: A WordPress server was compromised through a vulnerable plugin — the attacker modified PHP files — but there was no monitoring in place to detect file changes, and the compromise was discovered only after visitor complaints.
Solution: Configure auditd to monitor writes to the WordPress root: auditctl -w /var/www/html -p wa -k wordpress_writes. Query events with ausearch -k wordpress_writes and use aureport for summaries. Set up log forwarding to a remote syslog server so audit logs survive a compromised server. Complement with daily sha256sum baseline comparisons for batch file integrity checks.
The rules below configure auditd to monitor WordPress-critical paths, detect PHP execution in the uploads directory (a common webshell indicator), alert on wp-config.php modification, and export structured JSON logs to a SIEM via audispd.
# Install auditd
apt install auditd audispd-plugins
# /etc/audit/rules.d/wordpress.rules
# ── Watch wp-config.php for any write or attribute change ────────────────
-w /var/www/html/wp-config.php -p wa -k wp_config_tamper
# ── Watch wp-content/uploads for PHP file creation (webshell detection) ──
-w /var/www/html/wp-content/uploads -p w -k uploads_write
# Supplement with inotifywait for real-time alerting (see below)
# ── Watch WordPress core directory for unexpected writes ─────────────────
-w /var/www/html/wp-includes -p w -k wp_core_write
-w /var/www/html/wp-admin -p w -k wp_admin_write
# ── Monitor PHP binary execution (catches php -r "..." webshell calls) ───
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/php8.2 -k php_exec
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/php -k php_exec
# ── Monitor sudo and su for privilege escalation ──────────────────────────
-w /bin/su -p x -k priv_escalation
-w /usr/bin/sudo -p x -k priv_escalation
# ── Make rules immutable (require reboot to change) ──────────────────────
-e 2
# Apply rules and enable auditd
augenrules --load
systemctl enable --now auditd
# Search audit logs for wp-config.php events
ausearch -k wp_config_tamper -i | tail -20
# Real-time alert: PHP files written to uploads directory
inotifywait -m -r -e create --format '%T %w%f' --timefmt '%Y-%m-%d %H:%M:%S' \
/var/www/html/wp-content/uploads \
| while read DATE TIME FILE; do
if [[ "$FILE" =~ \.(php|php5|phtml|phar)$ ]]; then
echo "ALERT: PHP file created in uploads: $FILE at $DATE $TIME" \
| mail -s "Webshell Alert" security@example.com
fi
done &
NOTE: The -e 2 rule at the end of audit.rules locks the audit configuration and makes it immutable until reboot — an attacker who gains root access cannot disable auditing without rebooting the server; include this in production rules only after thorough testing, as it also prevents legitimate rule changes without a reboot.