Linux applications may make use of dynamically linked shared object libraries (let’s just call them shared libraries from now on) to provide application functionality without having to re-write the same code over and over - a bit like a .DLL in Windows applications. Like in a DLL planting attack on windows, Linux shared Libraries combined with weak file permissions can be used to execute arbitrary code and compromise Linux system.
How Does the OS Find a Shared Library?
When an application that uses shared libraries runs, the OS searches for the library in the following order (taken from https://linux.die.net/man/1/ld):
- Any directories specified by rpath-link options (directories specified by rpath-link options are only effective at link time)
- Any directories specified by –rpath options (directories specified by rpath options are included in the executable and used at runtime)
- Directories in the DT_RUNPATH or DT_RPATH. (DT_RPATH entries are ignored if DT_RUNPATH entries exist
- /lib and /usr/lib
- Directories within /etc/ld.so.conf
How can we get Root?
If an attacker can replace a shared library with a malicious one, then - when the application runs - it will load the malicious code and run it with the executing owner’s permissions. If an application is run as the Root super user, this would result in a full compromise of the host.
An attacker may need to be patient and wait for the application to be run by a user, or use an element of social engineering to trick a system administrator into executing the application that runs their malicious code. If the application is called at system start up, by a cron job, or by a process, exploitation could be quicker.
To identify a binary that uses shared libraries the ldd tool can be used:
The following attack paths can be followed to identify if a binary that uses shared libraries is going to be vulnerable to attack:
I am going to demonstrate an example whereby a binary compiled with an RPATH combined with weak file permissions can result in root privileges being gained.
Running ldd on the binary tells us that is uses shared libraries:
When objdump is run you can see that it has been compiled with a static RPATH pointing at /tmp/program/main:
The /tmp partition is by default world writeable and if it has been created without the NOEXEC flag will allow an attacker to write a malicious shared library here which will execute when the “contextBinary” is run. On the server in question, there is a root cronjob that just so happens to execute the vulnerable binary:
In this example we’re going to use the metasploit framework to create a shared library that we can plant on the system. First a handler is set up on the attacker’s host:
Then the malicious library is created. As we are exploiting the first place the OS will look for a shared library we can imitate any of the libraries that the application uses:
I’ve used msfvenom to create a shared library with the same payload as my handler:
On the vulnerable host, the directory structure is created and the library is made world writeable:
Once the cronjob runs, the malicious library is executed and in our metasploit console we have a shell session successfully running as root:
How do I defend against this?
Ok so that’s the offensive side of the blog post over with if you’re on the other side of the story you can harden your Linux host to defend from this attack.
As a systems administrator:
The attack comes down to weak file permissions so ensuring that low privileged users cannot write to:
- Locations specified in RPATH or RUNPATH
- Locations specified in LD_RUN_PATH and LD_LIBRARY_PATH environment variables
- /lib or /usr/lib
- Locations specified in /etc/ld.so.conf
As a developer:
If a library has to be compiled with RPATH or RUNPATH then specify the directory to be one that only the binary owner or root can write to. Alternatively specify the $ORIGIN variable which will resolve to wherever the binary is at runtime.
Alternatively, the libraries can be moved to /lib or /ur/lib and then the RPATH or RUNPATH removed from a compiled binary by using the chrpath tool.
Other things to be aware of:
- Execute applications with the least privileges needed. A malicious binary that is called by Root will result in a full compromise of your host
- Consider setting the NOEXEC option on the /tmp partition
In this blog post we have demonstrated a way of escalating privileges on a Linux host by weak file permissions and hardcoded RPATHs. There are other ways that shared libraries could be exploited not mentioned here.
- - -
Context can help you identify if your Linux host is vulnerable to such an attack by performing a review of a host or your organisations standard build.