Many people may not know this, but fifteen…twenty years ago I knew a thing or two about rootkit development. I wrote detection software for a few years as well. Back then modifying the shared libraries on the disk was also vector for userland rootkits.
There is a nicely written analysis of a clever little userland rootkit for Linux.
Userland rootkits are stable across systems and system upgrades. The downside for the attacker is that they run at the same privilege level as the defender. For the defender userland rootkits are a nuisance, easily handled and mitigated.
Lets explore the topic of userland rootkits and how to defeat them some more.
The first issue to address is that userland rootkits are terrible. They have their uses, but they’re just not robust against even minor investigation techniques. The details on this rootkit are quite impressive, clearly it is the result of a lot of development time. Maybe not so much research time though…
Let’s start with a summary of functionality, and then enumerate some simple techniques to detect and evade userland rootkits.
What it does. Badly.
Inject a library via
LD_PRELOAD into every process and use that to hide info from a user.
a shared object (SO) library that is loaded into all running processes using
The malware filters the process list read from /proc/ against an internal list of magic command names.
The malware filters the file system tree against an internal list of magic file names.
Stealth Evasion (lol)
ldd command is run, the malware scrubs itself from the list of loaded libraries.
A couple of techniques, including eBPF. They are all just some variant of hiding magic port numbers or magic domains.
All of this is really impressive and cool and not at all a complete and total waste of time.
This malware does a load of very clever complex and cool hiding tricks to make sure that network monitoring tools don’t capture the blessed packets. All of which is completely useless if someone thinks to statically compile
tcpdump, or wireshark, or whatever the kids are using these days.
busybox built as a static binary would negate all of these clever userland techniques. To ensure that other tools work, just statically compile them.
You can’t get a library injected into your process if you never load any libraries.
There are some easy ways to detect it. The simplest is to just use a staticky linked binary, like busybox, rather than the utilities on the compromised box. Honestly, I thought this was standard practise, so I’m a bit surprised that a userland rootkit causes problems for live forensics.
busybox. A statically linked binary like busybox is immune to infection via the dynamic linker, or via modified libraries on disk.
cat /proc/self/maps will show the memory layout of
cat, which will apparently be infected. If not, then just use the PID of your shell.
- The memory mappings will include the infecting library because apparently they don’t block this completely obvious method
Examine the stack for the environment variables. The report doesn’t mention if it cleans up, so maybe just running
/usr/bin/env will be enough to show
- If the malware does cleanup the environment variables, then use
ddand the info from the
/proc/pid/mapsto dump the top of the stack. The strings will be there, unless the malware zeroes out the memory, of course.
- If it *does* zero out the memory, then that overwriting will be visible in the memory dump. They can’t hide this because they would have to repack the string table, which would invalidate existing pointers to environment variables, causing system instability.
find to create a file list. Read the disk directly and dump out a “raw” file list from the actual file system structures. Compare the two. For an ext4fs the e2fsprogs package has debuggers and other tools which will help. It is pretty straight forward. I believe the Sleuthkit tools would be capable in this role as well.
Tired: userland rootkits
A statically compiled
busybox will completely negate the entirety of a userland rootkit. They are pretty weak.