How to Detect Rootkits with rkhunter
Install rkhunter, build a clean file-property baseline, tune the config to cut false positives, and automate daily scans with a systemd timer.
Before you start
- ▸Root or sudo access on the target system
- ▸A clean, freshly installed or recently patched OS (build the baseline before production traffic begins)
- ▸Outbound HTTPS access for database updates, or the data files pre-downloaded
- ▸A working MTA or mail relay if you want email alerts (mailutils or s-nail on Debian/Ubuntu)
Rootkits are among the nastiest threats a Linux system can face—they burrow into the OS to hide processes, files, and network connections from ordinary inspection tools. rkhunter (Rootkit Hunter) scans for known rootkits, suspicious file permissions, hidden files, and common backdoor signatures. It won't replace a full incident-response workflow, but it gives you an automated tripwire that catches many real-world compromises early. This guide walks through installation, building a clean baseline, running scans, and scheduling automated checks.
Installing rkhunter
Install from your distribution's package manager. The package name is rkhunter everywhere.
Debian / Ubuntu
sudo apt update && sudo apt install -y rkhunter
Fedora / RHEL 9 / Rocky Linux
rkhunter is in the EPEL repository on RHEL-family systems. Enable EPEL first if you haven't already.
sudo dnf install -y epel-release
sudo dnf install -y rkhunter
Arch Linux
sudo pacman -S rkhunter
After installation, check the version to confirm it landed correctly:
rkhunter --version
Output will resemble Rootkit Hunter 1.4.6 (version varies by distro and release date).
Updating the Signature Database
Before scanning anything, update rkhunter's data files. These include the rootkit signatures, known-good file hash lists, and mirrors for third-party checks.
sudo rkhunter --update
You'll see each data file fetched or marked up-to-date. If your system has no outbound HTTP/S access, download the data files on another machine and copy them to /var/lib/rkhunter/db/ manually.
Building the Baseline (File Property Database)
This is the most important step—and the one people skip. rkhunter compares current file properties (hashes, permissions, ownership) against a stored baseline. If you build that baseline on an already-compromised system, you're capturing the attacker's changes as "normal." Run this immediately after a clean OS install or immediately after patching, before putting the system into service.
sudo rkhunter --propupd
This writes system binary properties to /var/lib/rkhunter/db/rkhunter.dat. After every legitimate package upgrade that touches system binaries (kernel, glibc, OpenSSH, sudo, etc.), re-run --propupd to avoid false positives on the next scan.
Automating propupd after package upgrades
On Debian/Ubuntu you can hook into apt with a post-invoke script. Create the file:
sudo tee /etc/apt/apt.conf.d/99rkhunter-propupd <<'EOF'
DPkg::Post-Invoke { "if [ -x /usr/bin/rkhunter ]; then /usr/bin/rkhunter --propupd --nocolors --quiet; fi"; };
EOF
On Fedora/Rocky, add an equivalent DNF plugin hook or simply document that --propupd must be run after dnf update touches system paths.
Running Your First Scan
Run a full interactive scan to see what rkhunter finds and to familiarise yourself with its output before automating it:
sudo rkhunter --check --sk
The --sk flag (skip keypress) runs all tests without pausing for confirmation after each section—useful when you want a complete report without babysitting the terminal. Drop --sk the first time if you want to read each section interactively.
Scan results are written to /var/log/rkhunter.log automatically. The terminal output color-codes findings: green for OK, yellow for warnings, red for potential threats.
Reading the report
After the scan completes, check the summary and grep for anything that needs attention:
sudo grep -E 'Warning|Found|Rootkit' /var/log/rkhunter.log
Many first-run warnings are benign—hidden files in /dev that your distro ships, or SSH configuration options rkhunter considers non-default. Investigate each warning individually before dismissing it.
Configuring rkhunter
The main configuration file is /etc/rkhunter.conf. Edit it to reduce noise from known-safe items on your system. Key options:
- MAIL-ON-WARNING — set to your admin email address to receive scan reports when warnings are found.
- MAIL_CMD — the command used to send mail; defaults to
mail, which requires a working MTA ormailutils/s-nail. - SCRIPTWHITELIST — whitelist known-good scripts flagged as suspicious (e.g.,
/usr/bin/egrepon older systems). - ALLOWHIDDENDIR / ALLOWHIDDENFILE — suppress warnings about hidden paths you know are legitimate (e.g.,
/dev/.udev). - SSH_CONFIG_DIR — point to your actual sshd config path if non-standard.
- PKGMGR — set to
DPKG,RPM, orPACMANso rkhunter can cross-check file hashes against the package manager's own database.
After editing, validate your configuration syntax:
sudo rkhunter --config-check
Automating Scans with a systemd Timer
Prefer systemd timers over plain cron—they log to the journal, support dependencies, and survive missed runs cleanly. If you genuinely prefer cron, a fallback is shown afterward.
Create the systemd service unit
sudo tee /etc/systemd/system/rkhunter-scan.service <<'EOF'
[Unit]
Description=rkhunter daily rootkit scan
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/rkhunter --check --sk --nocolors --quiet --report-warnings-only
StandardOutput=journal
StandardError=journal
EOF
Create the systemd timer unit
sudo tee /etc/systemd/system/rkhunter-scan.timer <<'EOF'
[Unit]
Description=Run rkhunter daily
[Timer]
OnCalendar=daily
RandomizedDelaySec=1800
Persistent=true
[Install]
WantedBy=timers.target
EOF
RandomizedDelaySec=1800 spreads load on systems with many timers firing at midnight. Persistent=true runs a missed scan on next boot.
Enable and start the timer
sudo systemctl daemon-reload
sudo systemctl enable --now rkhunter-scan.timer
Verify the timer is scheduled
systemctl list-timers rkhunter-scan.timer
Output shows the next trigger time and the last run time. You'll see NEXT, LEFT, LAST, and PASSED columns.
Cron fallback (optional)
If you're on a system without systemd (containers, Alpine with OpenRC), add a daily cron entry instead:
echo '0 3 * * * root /usr/bin/rkhunter --check --sk --nocolors --quiet --report-warnings-only 2>&1 | /usr/bin/mail -s "rkhunter report: $(hostname)" root' | sudo tee /etc/cron.d/rkhunter
Verifying the Setup
Do a dry-run of the service unit to confirm it executes cleanly before relying on the timer:
sudo systemctl start rkhunter-scan.service
sudo journalctl -u rkhunter-scan.service -n 50
You want to see the service exit with status 0 (no warnings) or review any warnings the journal captured. Also confirm the log file was updated:
sudo tail -20 /var/log/rkhunter.log
Troubleshooting Common Issues
- "File updated by package manager" warnings after upgrades — you forgot to run
sudo rkhunter --propupdafter the upgrade. Run it now, then re-scan. - Many SSH-related warnings — rkhunter checks
/etc/ssh/sshd_configfor settings it considers risky. Review each flagged option; add legitimate deviations to theALLOWSSHPROTwhitelist inrkhunter.conf. - "Unable to find the command 'strings'" — install
binutils:sudo apt install binutilsorsudo dnf install binutils. rkhunter uses it internally for binary inspection. - Database update fails (no network) — copy
mirrors.dat,backdoorports.dat, and the other.datfiles from a connected machine into/var/lib/rkhunter/db/. - False positives filling the log — use
--config-checkand the whitelist directives inrkhunter.confto silence known-safe paths. Never whitelist something you haven't personally verified.
Frequently asked questions
- How often should I run rkhunter?
- Daily is the standard recommendation for internet-facing servers. For low-exposure internal machines, weekly is acceptable, but daily catches compromises before attackers have time to cover further tracks.
- Does rkhunter detect zero-day rootkits?
- No. rkhunter relies on known signatures and heuristics like suspicious file permissions and hidden processes. It will not catch a novel rootkit that hasn't been added to its database, which is why keeping the database updated and maintaining the file-property baseline both matter.
- What should I do if rkhunter reports a real rootkit?
- Isolate the machine from the network immediately. Do not trust any binaries on the compromised system, including rkhunter itself, for forensics—boot from trusted read-only media. Restore from a known-good backup taken before the compromise and conduct a post-mortem to find the initial access vector.
- Why do I get so many warnings on the first scan?
- rkhunter's defaults are conservative. Many first-run warnings reflect legitimate distro-specific configurations—SSH options, hidden files in /dev, or perl/python interpreter paths. Work through them one at a time, verify each is benign, then whitelist it in rkhunter.conf.
- Should I use rkhunter alongside chkrootkit or other tools?
- Yes. No single scanner has complete coverage. Running both rkhunter and chkrootkit gives overlapping detection with different signatures. Tools like AIDE or Tripwire complement them by providing more rigorous file-integrity monitoring across the entire filesystem.
Related guides
Manage Secrets with Ansible Vault
Encrypt Ansible secrets with AES-256 using ansible-vault: encrypt files and inline vars, automate with password files, and isolate group-level secrets with vault IDs.
AppArmor Explained
Learn how AppArmor profiles work, how to switch between enforce and complain mode, create new profiles, and diagnose access denials on Ubuntu, Debian, and Arch.
Apply CIS Benchmarks with OpenSCAP
Use OpenSCAP and scap-security-guide to evaluate, report on, and remediate Linux systems against CIS Benchmarks — covering install, eval, and automation.
How to Audit a Linux System with auditd
Set up auditd on Linux to track file access, syscalls, and privilege use. Covers persistent rules, file watches, ausearch, and aureport across major distros.