Tracking down library injections on Linux
While not nearly commonly seen on Linux systems, library (shared object files on Linux) injections are still a serious threat. On interviewing Jaime Blasco from AT&T’s Alien Labs, I’ve become more aware of how easily some of these attacks are conducted.
In this post, I’ll cover one method of attack and some ways that it can be detected. I’ll also provide some links that will provide more details on both attack methods and detection tools. First, a little background.
Shared library vulnerability
Both DLL and .so files are shared library files that allow code (and sometimes data) to be shared by various processes. Commonly used code might be put into one of these files so that it can be reused rather than rewritten many times over for each process that requires it. This also facilitates management of commonly used code.
Linux processes often make use of many of these shared libraries. The ldd (display shared object dependencies) command can display these for any program file. Here are some examples:
$ ldd /bin/date linux-vdso.so.1 (0x00007ffc5f179000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f02bea15000) /lib64/ld-linux-x86-64.so.2 (0x00007f02bec3a000) $ ldd /bin/netstat linux-vdso.so.1 (0x00007ffcb67cd000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f45e5d7b000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f45e5b90000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f45e5b1c000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f45e5b16000) /lib64/ld-linux-x86-64.so.2 (0x00007f45e5dec000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f45e5af5000)
The linux-vdso.so.1 file (which may have a different name on some systems) is one that the kernel automatically maps into the address space of every process. Its job is to find and locate other shared libraries that the process requires.
One way that this library-loading mechanism is exploited is through the use of an environment variable called LD_PRELOAD. As Jaime Blasco explains in his research, “LD_PRELOAD is the easiest and most popular way to load a shared library in a process at startup. This environmental variable can be configured with a path to the shared library to be loaded before any other shared object.”
To illustrate how easily this is done, I created an extremely simple shared library and assigned it to my (formerly non-existent) LD_PRELOAD environment variable. Then I used the ldd command to see how this would affect a commonly used Linux command.
$ export LD_PRELOAD=/home/shs/shownum.so $ ldd /bin/date linux-vdso.so.1 (0x00007ffe005ce000) /home/shs/shownum.so (0x00007f1e6b65f000) <== there it is libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1e6b458000) /lib64/ld-linux-x86-64.so.2 (0x00007f1e6b682000)
Note that doing nothing more than assigning my new library to LD_PRELOAD now affects any process that I run.
Since the libraries specified by the LD_PRELOAD setting are the first to load (following linux-vdso.so.1), those libraries could significantly change a process. They could, for example, redirect system calls to their own resources or make unexpected changes in how the process being run behaves.
The osquery tool can detect library injections
The osquery tool (downloadable from osquery.io is a tool that provides a very unique way of looking at Linux systems. It basically represents the operating system as a high-performance relational database. And, as you probably suspect, that means it can be queried and SQL tables created that provide details on such things as:
- Running processes
- Loaded kernel modules
- Open network connections
One kernel table that provides information on running processes is called process_envs. It provides details on environment variables used by various processes. With a fairly complicated query provided by Jaime Blasco, you can get osquery to identify processes that are using LD_PRELOAD.
Note that this query pulls data from the process_envs table. The attack ID (T1055) is a reference to Mitre’s explanation of the attack method:
SELECT process_envs.pid as source_process_id, process_envs.key as environment_variable_key, process_envs.value as environment_variable_value, processes.name as source_process, processes.path as file_path, processes.cmdline as source_process_commandline, processes.cwd as current_working_directory, 'T1055' as event_attack_id, 'Process Injection' as event_attack_technique, 'Defense Evasion, Privilege Escalation' as event_attack_tactic FROM process_envs join processes USING (pid) WHERE key = 'LD_PRELOAD';
Note that the LD_PRELOAD environment variable is at times used legitimately. Various security monitoring tools, for example, could use it, as might developers while they are troubleshooting, debugging or doing performance analysis. However, its use is still quite uncommon and should be viewed with some suspicion.
It’s also worth noting that osquery can be used interactively or be run as a daemon (osqueryd) for scheduled queries. See the reference at the bottom of this post for more on this.
You might also be able to locate use of LD_PRELOAD by examining users’ environment settings. If LD_PRELOAD is configured in a user account, you might determine that with a command like this (after asssuming the individual’s identity):
$ env | grep PRELOAD LD_PRELOAD=/home/username/userlib.so
If you’ve not previously heard of osquery, don’t take it too hard. It’s now in the process of becoming a more popular tool. Just last week, in fact, the Linux Foundation announced its intention to support the osquery commmunity with a brand-new osquery foundation.
Wrap-up
While library injection remains a serious threat, it’s helpful to know that some excellent tools are available to help detect its use on your systems.
Additional resources
Links to important references and tools:
READ MORE HERE