How Does rkhunter Scan for Rootkits?
Not long time ago, I used a useful tool rkhunter
to scan my system for possible rootkits and other vulnerabilities. The first time I came across rkhunter was on Arch wiki site. However, I had not much idea about how the scan for rootkits actually works. After some time spent reading, I’d like to share a thing or two about how rkhunter actually works. It might shed some light on the whole idea of rootkits as well.
Install rkhunter
First, let’s get rkhunter on your machine. I’m using Manjaro, so it’s easy via its pacman package manager:
$ pacman -Syu rkhunter
My current version is:
$ pacman -Qs hunter
local/rkhunter 1.4.6-1
Checks machines for the presence of rootkits and other unwanted tools.
Wikipedia says, rkhunter is included in some Linux distributions, so you might even already have it installed.
Rootkits - How It Works?
I won’t share much about how to use rkhunter, just read the Arch wiki, that’s enough information for you to be able to use it. However, I will share a bit about how rootkits work. I can have much more knowledge about this, however, as a general overview, this should be enough, so you get an idea what such a software can do.
A rootkit is in its essence just a piece of software that reside on your machine. It can be one or a couple of files somewhere on your filesystem. As it will turn out later, this is the key information, but let’s not skip other interesting parts.
As the name suggest, rootkit is here to gain access to your privileged account. It does so via a variaous means, and I guess I’m not anywhere near to knowing all of them. However, one way could be exploiting a vulnerability of one of your daemons by sending packets that allow the attacker to e.g. escalate permissions. One example from history would be Adm rootkit that were able to cause a buffer overflow of a DNS server running on TCP port 53. Another way attackers might use is a simple old social engineering or direct access to a targeted machine.
Advice number one on how not to get any rootkits:
- update your daemons regularly
- don’t share your credentials
- use a correctly configured firewall to protect you from traffic that you don’t want to receive
Once a rootkit is on your machine, it might do various things depending on what the attackers want it to do. I guess everyone can name a few, but to make this article complete, let’s come up with a few ideas:
- it can create a backdoor into your system as in the example of Beastkit that installed its own daemon that would be started at boot on a certain port (again, configure your firewall)
- it can tamper with some valid binaries on your system; it turns out this is a standard practise of rootkits because the attacker wants them to be hidden (for obvious reasons), so the rootkits might use their own versions of programs such as
ps
,top
,find
,md5sum
, etc. that don’t give you real results; some of these tampered versions are created with$ touch -acmr
options, so you have no way of finding a tampered binary by comparing its time - it can send information found on your system to the attacker
- it can tamper with your files, delete them, add something into them
- it can replicate itself by scanning suitable ports and ip addresses; again, this seems to be a common behaviour of rootkits
Therefore, advice number two on how to protect yourself would be:
- after a fresh installation of your system, run an integrity check and store this information somewhere outside your machine; therefore you can later compare the versions and find out if you have a tampered software like
netstat
,ps
and other - monitor your network traffic and ports; well, you should know what’s going on on your machine anyway, but provided you don’t monitor your traffic with a tool that’s been tampered with, it will prove useful in uncovering rootkits
- monitor processes and daemons on your machine; the same piece of advice from the previous point applies here as well
Rkhunter - How It Works?
It turns out rkhunter is a Bourne-shell script, so let’s find out what it contains. First, it’s a pretty long script:
$ sudo wc -l rkhunter
21646 rkhunter
So, enjoy reading it all :) But let’s have a look at some parts. If you check the end of the script, you get something like this:
sudo tail -n 80 rkhunter
fi
######################################################################
#
# Start of program actions and checks
#
######################################################################
#
# We can now start to run the actions the user has requested on
# the command-line. We run the update type commands first before
# doing any full system check.
#
#
# The user wants to update the O/S and the file properties data.
#
test $PROP_UPDATE -eq 1 && do_prop_update
#
# The user wants to update the supplied RKH *.dat files.
#
test $UPDATE -eq 1 && do_update
#
# The user wants to check for the latest program version.
#
test $VERSIONCHECK -eq 1 && do_versioncheck
#
# The user wants to check the local system for anomalies.
#
test $CHECK -eq 1 -o $ENDIS_OPT -eq 1 && do_system_check
#
# If there were errors or warnings, and the
# log file is to be copied, then log it.
#
COPIEDLOG=""
if [ $RET_CODE -gt 0 -o $WARNING_COUNT -gt 0 ]; then
if [ $COPY_LOG_ON_ERROR -eq 1 -a $NOLOG -eq 0 ]; then
COPIEDLOG="${RKHLOGFILE}.`date +%Y-%m-%d_%H:%M:%S`"
display --to LOG --type INFO --nl SUMMARY_LOGFILE_COPIED "${COPIEDLOG}"
fi
fi
display --to LOG --type INFO --nl RKH_ENDDATE "`date`"
#
# Now actually copy the log file.
#
test -n "${COPIEDLOG}" && cp -p "${RKHLOGFILE}" "${COPIEDLOG}"
#
# If the user asked to see the logfile, then show it.
#
test $CATLOGFILE -eq 1 && cat "${RKHLOGFILE}"
IFS=$ORIGIFS
exit $RET_CODE
That’s where it actually starts. The actual check is started by giving rkhunter --check
, --check-all
or --checkall
(see line 20096) option on the command line, therefore, the following part is of interest:
test $CHECK -eq 1 -o $ENDIS_OPT -eq 1 && do_system_check
Let’s dig into it a bit more. Function do_system_check
initializes a few different checks, it all starts on line 18661 and it goes like this:
#
# We start with checks of some of the commands (binaries) and
# libraries on the system, to make sure that they have not
# been tampered with.
#
do_system_commands_checks
#
# Next are the rootkit checks.
#
do_rootkit_checks
#
# Next are some network port, and interface checks.
#
do_network_checks
#
# Next are checks of the files for the local host.
#
do_local_host_checks
#
# Next are checks on specific applications.
#
do_app_checks
Let’s go further and have a look at how do_rootkit_checks
looks like:
do_rootkit_checks() {
#
# This function carries out a sequence of tests for rootkits.
# This consists of the default files and directories check,
# possible rootkit checks, and checks for malware.
#
if `check_test rootkits`; then
display --to LOG --type INFO --screen-nl --nl STARTING_TEST rootkits
display --to SCREEN+LOG --type PLAIN --color YELLOW CHECK_ROOTKITS
else
if [ $VERBOSE_LOGGING -eq 1 ]; then
display --to LOG --type INFO --nl USER_DISABLED_TEST rootkits
fi
return
fi
rootkit_file_dir_checks
check_test known_rkts || check_test all && keypresspause
additional_rootkit_checks
malware_checks
trojan_checks
os_specific_checks
keypresspause
return
}
Again, there are various other functions that get executed. However, to see just a bit, let’s see how rkhunter scans the filesystem:
rootkit_file_dir_checks() {
#
# This function performs the check for known rootkit
# files and directories.
#
if `check_test known_rkts`; then
display --to LOG --type INFO --screen-nl --nl STARTING_TEST known_rkts
display --to SCREEN+LOG --type PLAIN --screen-indent 2 ROOTKIT_FILES_DIRS_START
else
if [ $VERBOSE_LOGGING -eq 1 ]; then
display --to LOG --type INFO --nl USER_DISABLED_TEST known_rkts
fi
return
fi
# 55808 Trojan - Variant A
SCAN_ROOTKIT="55808 Trojan - Variant A"
SCAN_FILES=${W55808A_FILES}
SCAN_DIRS=${W55808A_DIRS}
SCAN_KSYMS=${W55808A_KSYMS}
scanrootkit
# ADM Worm
SCAN_ROOTKIT="ADM Worm"
ROOTKIT_COUNT=`expr ${ROOTKIT_COUNT} + 1`
display --to LOG --type PLAIN --nl ROOTKIT_FILES_DIRS_NAME_LOG "${SCAN_ROOTKIT}"
if [ -f "/etc/passwd" ]; then
RKHTMPVAR=`grep 'w0rm' /etc/passwd`
if [ -z "${RKHTMPVAR}" ]; then
display --to LOG --type PLAIN --result NOT_FOUND --log-indent 2 ROOTKIT_FILES_DIRS_STR 'w0rm'
display --to SCREEN+LOG --type PLAIN --result NOT_FOUND --color GREEN --screen-indent 4 NAME "${SCAN_ROOTKIT}"
else
ROOTKIT_FAILED_COUNT=`expr ${ROOTKIT_FAILED_COUNT} + 1`
ROOTKIT_FAILED_NAMES="${ROOTKIT_FAILED_NAMES}${SCAN_ROOTKIT}, "
display --to LOG --type PLAIN --result FOUND --log-indent 2 ROOTKIT_FILES_DIRS_STR 'w0rm'
display --to SCREEN+LOG --type WARNING --result WARNING --color RED --screen-indent 4 NAME "${SCAN_ROOTKIT}"
display --to LOG --type PLAIN --log-indent 9 ROOTKIT_FILES_DIRS_STR_FOUND 'w0rm' '/etc/passwd'
fi
else
display --to SCREEN+LOG --type WARNING --result WARNING --color RED --screen-indent 4 NAME "${SCAN_ROOTKIT}"
display --to LOG --type PLAIN --log-indent 9 ROOTKIT_FILES_DIRS_NOFILE '/etc/passwd'
fi
# AjaKit Rootkit
SCAN_ROOTKIT="AjaKit Rootkit"
SCAN_FILES=${AJAKIT_FILES}
SCAN_DIRS=${AJAKIT_DIRS}
SCAN_KSYMS=${AJAKIT_KSYMS}
scanrootkit
# "Adore" Rootkit
SCAN_ROOTKIT="Adore Rootkit"
SCAN_FILES=${AKIT_FILES}
SCAN_DIRS=${AKIT_DIRS}
SCAN_KSYMS=${AKIT_KSYMS}
scanrootkit
That’s what I mentioned at the beginning, rootkits reside somewhere on your filesystem and rkhunter just looks for them. Therefore, if you take AjaKit Rootkit
as an example and look for AJAKIT_FILES
and AJAKIT_KSYMS
variables, you’ll get:
# AjaKit Rootkit
AJAKIT_FILES="/dev/tux/.addr
/dev/tux/.proc
/dev/tux/.file
/lib/.libgh-gh/cleaner
/lib/.libgh-gh/Patch/patch
/lib/.libgh-gh/sb0k"
AJAKIT_DIRS="/dev/tux
/lib/.libgh-gh"
AJAKIT_KSYMS=
In function scanrootkit
, this list of files and locations is looped over and if such a file is found and not whitelisted, it will report not ok status on the output, e.g. it can look like this in the log file:
[12:11:05] Checking for Apache Worm...
[12:11:05] Checking for file '/bin/.log' [ Found ]
[12:11:06] Warning: Apache Worm [ Warning ]
[12:11:06] File '/bin/.log' found
(In this case I just ran $ sudo touch /bin/.log
prior to the test)
This happens when the old way scan is in place, not the thorough check, but by default the option SCANROOTKITMODE=THOROUGH
is commented out in /etc/rkhunter.conf
.
Conclusion
I think this article already gets pretty long with all the examples of rkhunter. However, the point here should be that one of the checks rkhunter runs is a simple scan for specific files and folders on your filesystem. Rootkits are analyzed and the location(s) of their files are more or less known, therefore it can be hard-coded into rkhunter and simply checked with test
.
As for more advice on preventing your machines from rootkits, I don’t really have any. I guess, for a personal machine, this is more than enough if you behave yourself on the Internet. Make sure you keep integrity checks of your key binaries right after a fresh installation, don’t run any daemons you don’t need, use correctly configured firewall, don’t share your credentials, monitor your ports, traffic, and filesystem. Doing just some of it regularly should keep you safe and sound :) If you need more thorough checks, use tools such as rkhunter.