Rootkits are malicious programs that hide their presence in the system at the kernel or filesystem level. Regular scanning with rkhunter and chkrootkit lets you detect a compromised server.
Installing and configuring rkhunter
apt install rkhunter -y
# Update the hash database
rkhunter --update
rkhunter --propupd # Save current file properties as the baseline
# Run a full scan
rkhunter --check --sk --rwo # --sk = skip keypresses, --rwo = warnings only
Important /etc/rkhunter.conf settings
MAIL-ON-WARNING=admin@example.com
MAIL_CMD=mail -s "[rkhunter] Warning on $(hostname)"
CRON_DAILY_RUN=yes
# Exclude false positives
SCRIPTWHITELIST=/usr/sbin/adduser
ALLOWHIDDENFILE=/etc/.gitconfig
PKGMGR=DPKG # Use dpkg to verify packages
Installing and using chkrootkit
apt install chkrootkit -y
chkrootkit
# Output: INFECTED means a potential threat
# Output: not infected — clean
Automatic scheduled scanning
# /etc/cron.daily/rkhunter-check
#!/bin/bash
/usr/bin/rkhunter --cronjob --update --quiet 2>&1 | mail -s "rkhunter Daily Report - $(hostname)" admin@example.com
chmod +x /etc/cron.daily/rkhunter-check
What to do if a threat is detected
- Isolate the server — disconnect it from the network (do not power it off!)
- Create a disk image for forensic analysis
- Check running processes:
ps aux,netstat -tulnp - Check cron and startup entries:
crontab -l,systemctl list-units - Restore from a clean backup onto a new server
Best practice: Run
rkhunter --propupd right after installing a clean system and after every package update. This creates an up-to-date baseline for comparison during the next scan.
rkhunter false positives are common. Investigate every warning before concluding the server is compromised. Start by checking with
dpkg -V package.
Common scanner warnings explained
Warning: The command '/usr/bin/which' has been replaced by a script: /usr/bin/which— a classic false positive on Debian and Ubuntu, where/usr/bin/whichis a plain shell script rather than a binary. rkhunter expects a binary file and mistakes a normal distribution quirk for tampering.Warning: The SSH configuration option 'PermitRootLogin' has been set to 'yes'— this warning is about thesshdsetting itself, not an infection. It is fixed by editing/etc/ssh/sshd_config, not by hunting for a rootkit on disk.Warning: The file properties have changed for: /usr/sbin/adduser, along with the current and stored hash — reports that the file changed since the lastrkhunter --propupd. On its own this does not mean compromise if the change came from a routine package update viaapt.The following suspicious files and directories were found:— the section header in chkrootkit's output under which specific findings are listed. An empty list right under this header is the expected clean result.- The
System checks summaryat the end of rkhunter's output shows the number of warnings and the path to the detailed log at/var/log/rkhunter.log— that is what to check for any warning, rather than guessing from console fragments.
rkhunter versus chkrootkit
| Criterion | rkhunter | chkrootkit |
|---|---|---|
| File checksum verification | Yes, via the --propupd database | No |
| sshd and sudo configuration checks | Yes | No |
| Known rootkit signature scanning | Yes, an updatable database | Yes, a separate built-in list |
| Scheduled automation | A ready-made script in /etc/cron.daily | Needs to be set up manually |
| Project maintenance activity | Updated regularly | Updated noticeably less often |
| Useful to run together | The primary tool | A secondary cross-check with a different signature engine |
When rootkit scanners do not protect you
- As the only method of protection — both rkhunter and chkrootkit look for already-known signatures and typical traces; a targeted rootkit built for a specific victim can slip past both scanners unnoticed.
- Checking an already-compromised system with its own utilities — if an attacker gained root, they may have replaced the rkhunter or chkrootkit binaries themselves, or the libraries they depend on, and the scanner will honestly report "clean" even though that is no longer true. A real investigation needs a disk image and analysis from external media.
- Containers and immutable infrastructure, where the server is recreated from an image on every deploy — manually scanning for rootkits inside a container loses its point; the focus there is on image immutability and integrity checks before launch, not after.
- Production with a strict SLA on load during a full scan —
--checkwalks the entire filesystem and can cause noticeable disk load; such scans are scheduled for a low-load window rather than run manually at peak traffic.
Verifying that scanning is actually configured
# Confirm the file properties database exists and is not empty
ls -la /var/lib/rkhunter/db/rkhunter.dat
# Check the date of the last signature update
rkhunter --versioncheck
# Run a one-off check and look at the final summary right away
rkhunter --check --sk --rwo | tail -20
# Confirm the daily automated run is actually scheduled
ls -la /etc/cron.daily/rkhunter-check
A clean result means zero warnings in the System checks summary, a database file with a recent modification date, and an executable file in cron.daily with rwxr-xr-x permissions. If the cron file is missing or not executable, daily checks simply never run, regardless of what a manual scan showed.