☄️Linux Internals-based Privilege Escalation
Kernel Exploits
Kernel level exploits exist for a variety of Linux kernel versions. A very well-known example is Dirty COW (CVE-2016-5195). These leverage vulnerabilities in the kernel to execute code with root privileges.
First we check the Kernel level and Linux OS version.
So here we have a Linux Kernel 4.4.0-116 on an Ubuntu 16.04.4 LTS box. After looking online we have linux 4.4.0-116-generic exploit
comes up with this exploit PoC. We need to compile the exploit code using gcc and set the executable bit
Then we can run it and hopefully we'll get a root shell
Shared Libraries
It is common for Linux programs to use dynamically linked shared object libraries. Libraries contain compiled code or other data that developers use to avoid having to re-write the same pieces of code across multiple programs.
There are static libraries
(denoted by the .a file extension) and dynamically linked shared object libraries
(denoted by the .so file extension)
the LD_PRELOAD
environment variable can load a library before executing a binary. The shared objects required by a binary can be viewed using the ldd
utility.
The output above lists all the libraries required by /bin/ls
To
escalate privileges with LD_PRELOAD we need a user with sudo
privileges.
we can exploit the LD_PRELOAD
issue to run a custom shared library file.
We can compile it with this command ->
And our privesc would look like this:
Shared Object Hijacking
Programs and binaries under development usually have custom libraries associated with them.
We can use ldd to print the shared object required by a binary or shared object.
We see a non-standard library named libshared.so
Now we can to load shared libraries from custom locations. To do this we can use the RUNPATH
configuration. Libraries in this folder are given preference over other folders. This can be inspected using the readelf utility.
The configuration allows the loading of libraries from the /development
folder, which is writable by all users.
placing a malicious library in /development
, which will take precedence over other folders because entries in this file are checked first
Before compiling a library, we need to find the function name called by the binary.
We can copy an existing library to the development
folder. Running ldd
against the binary lists the library's path as /development/libshared.
so, which means that it is vulnerable. Executing the binary throws an error stating that it failed to find the function named dbquery
. We can compile a shared object which includes this function.
Then we can compile
Python Library Hijacking
there are three basic vulnerabilities where hijacking can be used:
Wrong write permissions
Library Path
PYTHONPATH environment variable
Wrong Write Permissions
If we look at the set permissions of the mem_status.py
script, we can see that it has a SUID
set.
we can execute this script with the privileges of root
In the content of the python script there is this import ->
So we can look for this function in the folder of psutil
and check if this module has write permissions for us.
Content of the module:
This is the part in the library where we can insert our code.
we can insert the command id
and check during the execution of the script if the inserted code is executed.
So now we can insert a reverse shell that connects to our host as root
.
Library Path
The order in which Python imports modules
from are based on a priority system, meaning that paths higher on the list take priority over ones lower on the list.
To be able to use this variant, two prerequisites are necessary.
The module that is imported by the script is located under one of the lower priority paths listed via the
PYTHONPATH
variable.We must have write permissions to one of the paths having a higher priority on the list.
Our goal is that Python accesses the first hit it finds and imports it before reaching the original and intended module.
earlier we saw that psutil
module was imported into the mem_status.py
script. This is how We can see psutil
's default installation location
Now we can start to see if there might be any misconfigurations in the environment to allow us write
access to any of them.
/usr/lib/python3.8
path is misconfigured in a way to allow any user to write to it. Cross-checking with values from the PYTHONPATH
variable, we can see that this path is higher on the list than the path in which psutil
is installed in. Let us try abusing this misconfiguration to create our own psutil
module containing our own malicious virtual_memory()
function within the /usr/lib/python3.8
directory.
we need to create a file called psutil.py ->
and if once again we run the mem_status.py
script using sudo
like in the previous example.
PYTHONPATH Environment Variable
PYTHONPATH
is an environment variable that indicates what directory (or directories) Python can search for modules to import. This is important as if a user is allowed to manipulate and set this variable while running the python binary, they can effectively redirect Python's search functionality to a user-defined
location when it comes time to import modules.
we are allowed to run /usr/bin/python3
under the trusted permissions of sudo
and are therefore allowed to set environment variables for use with this binary by the SETENV:
flag being set.
This means that using the /usr/bin/python3
binary, we can effectively set any environment variables under the context of our running program. Let's try to do so now using the psutil.py
script
we moved the previous python script from the /usr/lib/python3.8
directory to /tmp
. From here we once again call /usr/bin/python3
to run mem_stats.py
, however, we specify that the PYTHONPATH
variable contain the /tmp
directory so that it forces Python to search that directory looking for the psutil
module to import.
Follow along with the examples in this section to escalate privileges. Try to practice hijacking python libraries through the various methods discussed. Submit the contents of flag.txt under the root user as the answer.
for this one i had a hard time, we need to write the psutil.py in the same directory as mem_status.py and run it using this command ->
Last updated