Tune chkrootkit-daily Reports Without Hiding Alerts
A daily rootkit report nobody reads is worse than none, and a report filtered until it is silent is worse still. This guide sets up Debian's chkrootkit-daily job, builds a known-good baseline and shows you when a later report needs investigating. It uses chkrootkit 0.58b-1, with the scanner reporting version 0.58b, and takes about 20 minutes for the first run and baseline review.
The route
Jump straight to the step you need, or tick off Done means at the end.
- You need: a shell and a user who can use
sudo. The daily job itself normally runs with elevated privileges from its timer or cron. - What it is not. This is a local rootkit check, not proof a machine is clean. It can report false positives, and an attacker with control of the host may be able to interfere with local tools or their output.
- Keep the raw report. Investigate unexpected changes separately.
1. Confirm the installed command and scheduler
Start with read-only checks. They do not need sudo:
$ command -v chkrootkit-daily
/usr/sbin/chkrootkit-daily
$ dpkg-query -W -f='\${Package} \${Version}\n' chkrootkit
chkrootkit 0.58b-1
$ chkrootkit -V
chkrootkit version 0.58b
$ systemctl list-timers --all 'chkrootkit*' --no-pager
The manual describes chkrootkit-daily as suitable for a systemd timer or a cron job. On a systemd host, the last command should show chkrootkit.timer if the packaged timer is installed. Do not enable a second scheduler just because one command printed nothing: check your distribution's package files and existing cron configuration first.
Checkpoint
You know which package and scheduler are present. If the binary or timer is missing, stop and use your normal package-management process rather than copying a script from elsewhere.
2. Read the configuration before changing it
The configuration file is /etc/chkrootkit/chkrootkit.conf. The daily script sources it as shell code, so it must stay valid shell syntax and be owned and writable only by trusted administrators. Read it without changing anything:
$ sudo sed -n '1,220p' /etc/chkrootkit/chkrootkit.conf
$ sudo test -r /etc/chkrootkit/chkrootkit.ignore && sudo sed -n '1,120p' /etc/chkrootkit/chkrootkit.ignore || echo 'no ignore file'
The settings that matter are RUN_DAILY, RUN_DAILY_OPTS, DIFF_MODE, FILTER, IGNORE_FILE and MAILTO. The packaged defaults:
- Enable the daily run.
- Pass no scanner options.
- Compare output with an expected file.
- Normalise changing process identifiers and network-manager messages.
- Send the report to
root.
Your installed file is authoritative if it differs from those defaults.
Warning
Do not treat FILTER or the ignore file as a way to make an alert disappear. A filter can rewrite output, and each line in IGNORE_FILE is an extended regular expression that removes matching lines. Every removed line is evidence you will no longer see.
3. Choose reporting and email deliberately
Decide where the report should arrive before you edit anything. This is a persistent, security-sensitive change. Make a backup first, then use an editor that preserves the file's ownership and permissions:
$ sudo cp -a /etc/chkrootkit/chkrootkit.conf /etc/chkrootkit/chkrootkit.conf.bak
$ sudoedit /etc/chkrootkit/chkrootkit.conf
- Leave
RUN_DAILY_OPTS=""at first. The report then contains all scanner output. - Keep
DIFF_MODE="true"if you want routine output compared with a baseline. - Set
MAILTO="[email protected]"to a local address or account your mail system can deliver to. IfMAILTOis empty, output stays on standard output, which normally means the systemd journal or a cron-generated message. - For the full filtered report every day, set
DIFF_MODE="false". In that modeRUN_DAILY_OPTS="-q"can reduce noise, but quiet mode suppresses tests that find nothing suspicious, so do not add-qmerely to shorten the email.
Check the edited file before running it:
$ sudo sh -n /etc/chkrootkit/chkrootkit.conf
$ sudo grep -E '^(RUN_DAILY|RUN_DAILY_OPTS|DIFF_MODE|IGNORE_FILE|MAILTO)=' /etc/chkrootkit/chkrootkit.conf
Recovery
A non-zero result from sh -n means the daily job may fail before scanning. Undo the edit with sudo cp -a /etc/chkrootkit/chkrootkit.conf.bak /etc/chkrootkit/chkrootkit.conf.
4. Run the first scheduled scan
The daily command writes under /var/log/chkrootkit, so this step needs elevated privileges and changes host state. It can take a little while, and you should not run it at the same time as the timer:
$ systemctl list-timers --all 'chkrootkit*' --no-pager
$ sudo systemctl start chkrootkit.service
$ sudo systemctl status --no-pager chkrootkit.service
The service should finish without an active process left behind. A successful service run is not the same as a clean scan, so inspect the report and the files it creates:
$ sudo ls -l /var/log/chkrootkit/
$ sudo sed -n '1,160p' /var/log/chkrootkit/chkrootkit-daily.log
$ sudo sed -n '1,160p' /var/log/chkrootkit/log.today
$ sudo sed -n '1,80p' /var/log/chkrootkit/log.today.raw
Which file is which:
log.today.rawholds the raw scanner output.log.todayis that output afterFILTERandIGNORE_FILEhave been applied.chkrootkit-daily.logholds the wrapper's own messages and the final report.
Variable process IDs and normal network-manager notices are why the default filter exists. A line containing INFECTED, an unexpected binary or an unfamiliar process is a reason to investigate, not a reason to add a new ignore pattern.
5. Create and review the expected baseline
With diff mode enabled, the first run tells you that /var/log/chkrootkit/log.expected does not exist. Review log.today and the raw file first, and only set a baseline when you understand every remaining line:
$ sudo diff -u /var/log/chkrootkit/log.today /var/log/chkrootkit/log.today.raw || true
$ sudo cp -a /var/log/chkrootkit/log.today /var/log/chkrootkit/log.expected
The first command may show differences, because filtering is expected. The second is an elevated, persistent change that replaces any existing expected file, so back that up first if one exists:
$ sudo test -f /var/log/chkrootkit/log.expected && sudo cp -a /var/log/chkrootkit/log.expected /var/log/chkrootkit/log.expected.bak
$ sudo cp -a /var/log/chkrootkit/log.today /var/log/chkrootkit/log.expected
On a later run, unchanged filtered output produces no alert text. A changed report prints a unified diff between log.expected and log.today. Compare the change with the raw output before you edit the baseline.
Recovery
To undo a baseline update, restore log.expected.bak. If it was a new file, remove only that file, and only after checking that no current investigation needs it.
6. Use scanner options sparingly
chkrootkit supports these options, and the daily wrapper passes RUN_DAILY_OPTS to the scanner:
-qfor quiet output.-xfor expert detail.-dfor debug output.-efor named exclusions.-sfor sniffer-test exclusions.-nto ignore NFS directories.-lto list tests.
Options cannot be combined, so write -q -n, not -qn.
Use exclusions only when you have recorded why a result is a known false positive. A standard network manager showing up in the sniffer test is the classic case. Prefer the documented -s regular expression or a narrow ignore pattern, and keep the raw report so the original evidence survives.
Warning
Never use -r or -p in the daily job without testing the alternate root or trusted command path separately.
Done means
- The setup is confirmed. You know the installed package and scheduler.
- The config parses.
/etc/chkrootkit/chkrootkit.confpasses shell syntax checking. - Reports arrive. They reach the intended local address, or are available in the journal or cron mail.
- All three logs were read. That means
log.today.raw,log.todayandchkrootkit-daily.log. - The baseline was reviewed first. The expected file was created only after its contents were checked.
- Findings come from the raw report. Unexpected results are investigated, not hidden with filters or ignores.