Rootkit Hunter is, as its name describe, a rootkits detection tool. It can detect if a system has been compromised. It is a required tool for checking a system health. This guide describe how to configure rkhunter on Debian.

This howto is tested on:

  • Debian 10.0 Buster

This howto is tested with these versions of the software:

  • 1.4.6


This howto recommends:


Set the external email address to which rootkits alerts are sent (set to local root account by default):



Detect if sudo is available (“command” is used if not):

command type -f 'sudo' &>'/dev/null' && cmdProxy='sudo'

Install the software and its requirements:

${cmdProxy} apt install 'rkhunter' 'bsd-mailx'


Create the modular configuration folder:

${cmdProxy} mkdir --parent '/etc/rkhunter.d'

Email notifications

Enable email notifications when the software find a problem:

${cmdProxy} tee '/etc/rkhunter.d/mail-on-warning.conf' <<< "#
# Email a message to this address if a warning is found when the system is
# being checked.

# This option specifies the mail command to use if MAIL-ON-WARNING is set.
#MAIL_CMD=mail -s \"[rkhunter] Warnings found for ${HOST_NAME}\""

Enable all tests

By default, allow for all available tests:

${cmdProxy} sed -i -e 's/^DISABLE_TESTS=/#&/' '/etc/rkhunter.conf'

Enable all available tests:

${cmdProxy} tee '/etc/rkhunter.d/enabled-tests.conf' <<< "#
# These two options determine which tests are to be performed. 

Updates downloading

Choose the tool used to download updates:

${cmdProxy} tee '/etc/rkhunter.d/web-updates.conf' <<< "#
# If this option is set to '1', it specifies that when the '--update' option is
# used, then the mirrors file is to be checked for updates as well. 

# The MIRRORS_MODE option tells rkhunter which mirrors are to be used when
# the '--update' or '--versioncheck' command-line options are given.
#     0 - use any mirror

# The following option can be set to a command which rkhunter will use when
# downloading files from the Internet - that is, when the '--update' or
# '--versioncheck' option is used. The command can take options.

Enable weekly updates of the threats database:

[[ -e '/etc/default/rkhunter' ]] \
  && ${cmdProxy} sed -i -e 's/^CRON_DB_UPDATE=.*$/CRON_DB_UPDATE="true"/' '/etc/default/rkhunter'

Files properties

Enable the checking of installed files properties against DPKG packages information:

${cmdProxy} tee '/etc/rkhunter.d/pkgmgr.conf' <<< "#
# The HASH_CMD option can be used to specify the command to use for the file
# properties hash value check.
# NOTE: Whenever this option is changed 'rkhunter --propupd' must be run.

# The PKGMGR option tells rkhunter to use the specified package manager to
# obtain the file property information. 
# NOTE: Whenever this option is changed 'rkhunter --propupd' must be run.
# Running --propupd takes about 4 times longer when it's set to DPKG

Enable auto update of the files properties database when apt is called:

[[ -e '/etc/default/rkhunter' ]] \
  && ${cmdProxy} sed -i -e 's/^APT_AUTOGEN=.*$/APT_AUTOGEN="true"/' '/etc/default/rkhunter'

System.d networkd

Allow systemd-networkd to listen on network:

[ -x '/lib/systemd/systemd-networkd' ] \
  && ${cmdProxy} tee '/etc/rkhunter.d/systemd-networkd.conf' <<< "#
# Allow systemd-networkd to listen on network.

Scripts whitelist

Trust “/usr/bin/which” symbolic link to “/bin/which” to be a script:

[ -h '/usr/bin/which' \
    -a "$(command ls -l '/usr/bin/which' \
        | command cut --delimiter=' ' --fields=13)" = '/bin/which' ] \
  && ${cmdProxy} tee '/etc/rkhunter.d/script-whitelist.conf' <<< "#
# Allow /usr/bin/which symbolic link to /bin/which to be a script.

Deleted file usage whitelist

Allow some trusted processes the use of deleted files:

[ ! -e '/etc/rkhunter.d/allow-hidden-dir.conf' ] \
  && ${cmdProxy} tee '/etc/rkhunter.d/allow-hidden-dir.conf' <<< "#
# Allow the specified process to use deleted files. The process name may be
# followed by a colon-separated list of full pathnames (which have been
# deleted). The process will then only be whitelisted if it is using one of
# the given pathnames. For example:
#     ALLOWPROCDELFILE=/usr/libexec/gconfd-2:/tmp/abc:/var/tmp/xyz"
while read -a trustedProcess; do
  if [ -x "${trustedProcess}" ]; then
    command grep --quiet "${trustedProcess}" '/etc/rkhunter.d/allow-hidden-dir.conf' 2>'/dev/null' \
    || ${cmdProxy} tee -a '/etc/rkhunter.d/allow-hidden-dir.conf' \
    <<< "ALLOWPROCDELFILE=${trustedProcess}"
done <<< "/lib/systemd/systemd-logind


Allow PHP-FPM to use deleted ZendSem files:

while read -a version; do
  # For each installed PHP-FPM version.
  if [ -n "${version}" ]; then
    command grep --quiet "php-fpm${version}" '/etc/rkhunter.d/php-fpm.conf' 2>'/dev/null' \
    || ${cmdProxy} tee -a '/etc/rkhunter.d/php-fpm.conf' <<< "
# Whitelist PHP-FPM ${version} usage of deleted ZendSem files.
done <<< "$(command dpkg-query --show 'php[0-9]*-fpm' 2>'/dev/null' \
  | command cut --delimiter=$'\t' --fields=2 \
  | command awk 'NF' \
  | command cut --delimiter='.' --fields=1-2)"

Allow Apache 2 to use deleted ZendSem files:

if [ -e '/etc/rkhunter.d/php-fpm.conf' -a -x '/usr/sbin/apache2' ]; then
  command grep --quiet "/usr/sbin/apache2" '/etc/rkhunter.d/php-fpm.conf' 2>'/dev/null' \
    || ${cmdProxy} tee -a '/etc/rkhunter.d/php-fpm.conf'  <<< "
# Allow Apache 2 to use ZendSem deleted files.

Allow Apache 2 to use secure System.d tmp directory for PHP:

if [ -e '/etc/rkhunter.d/php-fpm.conf' -a -x '/usr/sbin/apache2' ]; then
  command grep --quiet "apache2.service" '/etc/rkhunter.d/php-fpm.conf' 2>'/dev/null' \
    || ${cmdProxy} tee -a '/etc/rkhunter.d/php-fpm.conf'  <<< "
# Allow Apache 2 to store PHP related files in secure System.d tmp directory.


Allow Gunicorn to use deleted files:

while read -a gunicornRunner; do
  if [ -n "${gunicornRunner}" -a -x "${gunicornRunner}" ]; then
    command grep --quiet "${gunicornRunner}" '/etc/rkhunter.d/gunicorn.conf' 2>'/dev/null' \
      || ${cmdProxy} tee -a '/etc/rkhunter.d/gunicorn.conf'  <<< "
# Allow Gunicorn to use deleted files.
done <<< "$(${cmdProxy} ps ax \
  | command grep -v 'grep' | command grep -e 'gunicorn' \
  | command cut --delimiter=' ' --fields=2 \
  | command xargs -iPID readlink -f '/proc/PID/exe' | uniq)"

Xen ‘xl’ command

Allow for installed xen-utils ‘xl’ command:

while read -a version; do
  if [ -n "${version}" ]; then
    command grep --quiet "/xen-${version}/" '/etc/rkhunter.d/xen.conf' 2>'/dev/null' \
      || ${cmdProxy} tee -a '/etc/rkhunter.d/xen.conf' <<< "#
# Whitelist xl from xen-utils ${version}.
done <<< "$(command dpkg-query --show 'xen-utils-[0-9]*' 2>'/dev/null' \
  | command cut --delimiter=$'\t' --fields=2 \
  | command awk 'NF' \
  | command cut --delimiter='.' --fields=1-2)"

Byobu files in ‘/dev/shm’

Allow for byobu running files:

if [[ -n "$(command dpkg-query --show 'byobu' 2>'/dev/null' \
    | command cut --delimiter=$'\t' --fields=2 \
    | command awk 'NF')" ]]; then
  ${cmdProxy} tee '/etc/rkhunter.d/byobu.conf' <<< "#
# Whitelist byobu /dev/shm/ files.
  declare -a byobuFolders
  declare -a byobuFiles
  byobuFolders=( 'status.tmux' '.last.tmux' )
  byobuFiles=( 'cpu_count' 'cpu_freq' 'disk' 'load_average' 'logo' \
      'memory' 'release' 'session' 'uptime' )
  for byobuFolder in "${byobuFolders[@]}"; do
    for byobuFile in "${byobuFiles[@]}"; do
      ${cmdProxy} tee -a '/etc/rkhunter.d/byobu.conf' \
        <<< "ALLOWDEVFILE=/dev/shm/byobu-*-*/${byobuFolder}/${byobuFile}"

Allow remote SSH login by root user

Allowing root user to login directly by SSH is a bad idea. If you can not block the root SSH direct login, rkhunter must be configured to ignore this setting.

Disable the warning on allowed SSH login for root user (bad practice !):

if [[ -e '/etc/ssh/sshd_config' ]]; then
  allowSshRootUser="$(command grep '^PermitRootLogin' '/etc/ssh/sshd_config'  \
    | command sed -e 's/^PermitRootLogin[ \t]*\([^ \t]*\)[ \t]*.*$/\1/')"
  [[ -z "${allowSshRootUser}" ]] && allowSshRootUser='unset'
  ${cmdProxy} tee '/etc/rkhunter.d/allow-ssh-root-user.conf' <<< "#
# The following option is checked against the SSH configuration file
# 'PermitRootLogin' option. A warning will be displayed if they do not match.


Update the file properties database:

${cmdProxy} rkhunter --propupd

Update the threats database:

${cmdProxy} rkhunter --update

Run rkhunter for the first time to check if undue warnings are reported:

${cmdProxy} rkhunter --configfile '/etc/rkhunter.conf' \
    --report-warnings-only --checkall

Enable daily rootkit checks by rkhunter:

[[ -e '/etc/default/rkhunter' ]] \
  && ${cmdProxy} sed -i -e 's/^CRON_DAILY_RUN=.*$/CRON_DAILY_RUN="true"/' '/etc/default/rkhunter'


Categories: Security


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.