Scan Linux for Rootkits with chkrootkit and Investigate Safely
You will run the installed chkrootkit scanner, separate an ordinary finding from evidence that needs urgent investigation, and record a baseline without silently hiding new results. Allow about 20 minutes for a first scan and longer if a result needs checking. This guide uses Debian package chkrootkit 0.58b-1, whose command reports version 0.58b.
The route
Jump straight to the step you need, or tick off Done means at the end.
Safety boundary
A rootkit scan is diagnostic, not a repair. Do not delete a reported file, replace a system binary, edit an exclusion list or reboot a suspect host just because one line looks alarming. If you have credible evidence of compromise, preserve logs and seek incident-response help before changing the machine.
1. Confirm the installed scanner
Start with read-only checks. These commands do not need elevated privileges:
$ command -v chkrootkit
/usr/sbin/chkrootkit
$ chkrootkit -V
chkrootkit version 0.58b
$ dpkg-query -W -f='${Package} ${Version}\n' chkrootkit
chkrootkit 0.58b-1
The manual describes chkrootkit [OPTION]... [TESTNAME].... Its options cannot be combined, so use -q -n, not -qn. Keep that detail in scripts and runbooks because a compact option spelling can be rejected or interpreted differently than expected.
Checkpoint
You have confirmed the binary and package version. If command -v finds nothing, install the package through your normal distribution process before continuing. Do not download a replacement script into a privileged path.
2. List tests before running them
Ask the installed command which test names it accepts:
$ chkrootkit -l
/usr/sbin/chkrootkit: tests: aliens asp bindshell lkm rexedcs sniffer w55808 wted scalper slapper z2 chkutmp OSX_RSPLUG amd basename biff chfn chsh cron crontab date du dirname echo egrep env find fingerd gpm grep hdparm su ifconfig inetd inetdconf identd init killall ldsopreload login ls lsof mail mingetty netstat named passwd pidof pop2 pop3 ps pstree rpcinfo rlogind rshd slogin sendmail sshd syslogd tar tcpd tcpdump top telnetd timed traceroute vdir w write
A plain invocation checks all available tests. Passing names limits the run to those tests, which is useful for a focused follow-up, but a partial run is not a clean bill of health. For example, chkrootkit ps ls sniffer checks only those three test areas.
3. Run the full scan with elevated privileges
The scanner needs root privileges for its system and process checks. Run the complete scan from a terminal where you can review all output:
$ sudo chkrootkit
ROOTDIR is `/`
Checking `amd'... not found
Checking `basename'... not infected
... output varies by host ...
The exact lines depend on the host and installed commands. The older package documentation defines the main result labels: not infected means that test did not find a known signature; INFECTED means a test identified a command probably modified by a known rootkit; not tested means the check could not run; and not found means the command being tested is absent. A result of Vulnerable but disabled describes an infected command that is not currently in use.
A non-zero-looking or noisy result is not a diagnosis by itself. Save the raw output with a new filename if you need to share it, but treat the output as sensitive because it can expose host names, paths, process names and network details:
$ sudo chkrootkit 2>&1 | tee "$HOME/chkrootkit-$(date +%F).log"
$ grep -E 'INFECTED|Vulnerable|not tested|not found' "$HOME"/chkrootkit-*.log
The pipeline displays the scan while saving it. The second command is an ordinary read-only search of your saved log. Protect or remove the log according to your local incident-handling rules; do not email it casually.
4. Triage suspicious lines without filtering them away
First rerun the relevant test without -q, then inspect the named file, process or service independently. The quiet option suppresses tests that find nothing suspicious, so it is useful for routine review but poor for learning what a complete run did:
$ sudo chkrootkit -q
ROOTDIR is `/`
... only selected findings are shown ...
$ sudo chkrootkit ps ls sniffer
Common false positives include normal network managers reported as packet sniffers, legitimate processes without a terminal entry in utmp, executable files in /tmp, and dot-prefixed files under /usr/lib. A process that exits while the process check is running can also produce a misleading hidden-process result. Check package ownership, the process command line, service configuration and recent logs before deciding what a line means.
For extra evidence, -x enables expert output and shows additional strings found by many tests. It can produce a large amount of data, so write it to a protected file and review it deliberately:
$ sudo chkrootkit -x > chkrootkit-expert.txt 2>&1
$ less chkrootkit-expert.txt
Do not interpret a suspicious string as proof of infection. The test still needs context, such as whether the binary belongs to the expected package and whether its checksum matches trusted package metadata.
5. Use exclusions only after proving a false positive
The -e option excludes a space-separated list of files or directories from some results. This changes what you see, so use it only after you have verified the item and recorded why it is legitimate:
$ sudo chkrootkit -e '/known/legitimate/path'
$ sudo chkrootkit -e '/one/path /another/path'
Quote the whole list. You can also repeat -e. The manual and package documentation warn that exclusions can give an attacker a way to avoid detection. Keep a review date and periodically scan excluded paths without the exclusion. An exclusion is not an undo operation for a compromised file; if your assessment changes, stop using it and investigate the path normally.
The -s REGEXP option is narrower: it filters the packet-sniffer test. It is appropriate only when you recognise the expected network manager, for example:
$ sudo chkrootkit -s '(systemd-networkd|NetworkManager|wpa_supplicant)'
Check the regular expression before using it. A broad expression can hide a real sniffer alongside the expected process.
6. Check a mounted filesystem with trusted tools
If you need to inspect a disk from a separate, trusted system, mount it read-only according to that system's recovery procedure and pass its mount point with -r. This is an elevated, security-sensitive workflow:
# chkrootkit -r /mnt/suspect
The command treats /mnt/suspect as the root directory for the scan. Use -p DIR1:DIR2 to point at trusted copies of external commands, such as copies stored on trusted removable media:
# chkrootkit -p /media/trusted-tools -r /mnt/suspect
Verify both paths before running this. Do not use -r as a shortcut for scanning an arbitrary directory on the live host, and do not place unverified binaries in the alternate path. Unmount the evidence filesystem using the recovery system's documented procedure when the investigation is complete.
7. Make routine reviews comparable
For a regular review, keep the default full output and compare it with a known-good baseline only after you understand the host's normal findings. The Debian package supplies a daily wrapper and configuration under /etc/chkrootkit, but changing those files affects scheduled behaviour and is outside this one-off scan. Read the configuration before enabling or modifying any timer, cron job, filter or mail destination.
Keep the version, command line, date and host context with each report. A changed package version or normal service can explain changed output. A new INFECTED result, an unexplained process or a modified system binary warrants a separate investigation, not automatic deletion or replacement.
Done means
- The installed binary and package version were confirmed.
- A complete scan was run with elevated privileges and its sensitive output was stored safely.
- Each suspicious label was treated as a lead and checked against the host's packages, processes and logs.
- Quiet mode, expert mode, exclusions and sniffer filters were used only for a stated purpose.
- No reported file was deleted, replaced or hidden before the evidence was assessed.