Path Hijacking and Library Hijacking are two basic privilege escalation techniques, which when combined with, for example, SUID privilege or sudo, can become dangerous from a security standpoint.

Table of Contents:

What is the PATH?

When we execute a command in a terminal or cmd, how does the shell know that the word we’ve written corresponds to a command with X function. What decides whether a command is detected or not?:

Example of commands recognized and not recognized by the shell

All of this is thanks to the PATH. The path is an environment variable which contains system paths. When we execute a command, the system searches for a file with the name of the command we’ve written, in each path of the PATH.

That is, for example, when we write pwd, the system will search for a file with the same name in the following directories in the following order:

Visualization of the PATH on Linux showing the paths where commands are searched

The same would happen on Windows:

Visualization of the PATH on Windows showing system paths

And it also applies to programming languages, for example, Python:

Python path showing the paths where libraries are searched

This would be the path for when we want to load a library.

The path is only used when relative paths are written:

Comparison between command execution with relative and absolute path

In the first execution, the system used the path to find where the whoami binary was, however, in the second one it’s not necessary, because we already indicate where it is. So in the second way we can avoid attacks like path hijacking and library hijacking. For the development of any binary/script, it’s highly recommended to always use absolute paths, both for commands if we’re in a command language like bash or libraries if we’re in a programming language like Python for example.

Path Hijacking

To perform path hijacking I’ve created the following program in C:

C code vulnerable to Path Hijacking using head with relative path

As we can see, the program outputs the first 10 lines of the passwd file twice, the first one is done using the absolute path of head, and the second, in a relative way. At this point, we compile with gcc to create the binary:

Compilation of the vulnerable program with gcc

Note: in this case I do it with a compiled binary to be able to use the SUID permission properly.

To see more clearly the danger of not using absolute paths, I’m going to assign SUID permission to it:

Assignment of SUID permission to the vulnerable binary

With this, if we execute the binary from the normal user we’ll do it as the root user due to the SUID permission:

Execution of the binary with SUID permissions as normal user

With all this done, we’re going to carry out the Path Hijacking, if we do a strings on the binary we can identify that the command is being called in a relative way (this would be a possible way to identify it if we don’t have access to the original code):

Using strings to identify commands executed in a relative way

strings prints readable character strings

This way we can realize it, although it’s not always the case that we can see it.

Additionally, we can notice that setuid is being used in the code, this means that the code will execute with the user of the UID we indicate (careful, even if we put 0, it won’t execute as root if it doesn’t have the SUID permission, you need so to speak a double check, that’s why in addition to setuid at 0, we give it the SUID permission. This double check wouldn’t apply if we were the root user, since we have total privileges, so with setuid it would be enough).

At this point, we’re going to change the PATH by adding the current path and the PATH variable itself, to avoid command problems:

Modification of the PATH to include the current path

At this point, since the command we want to impersonate is head, we create a file with the same name that contains the command we want to execute, in my case, bash -p:

Creation of malicious file named head with the bash command

With the path changed to look in the current path and a file that impersonates the legitimate head, if we now execute the binary:

Successful exploitation of Path Hijacking obtaining root shell

We see how in the part of the code that executes head in a relative way, the command we’ve written is executed, this way we’ve executed a path hijacking (path hijack) and obtained a shell as root.

Library Hijacking

Understanding path hijacking, library hijacking is basically the same thing, just changing the practical aspect a bit. We’re going to use the following code in Python:

Python code vulnerable to Library Hijacking importing requests

As we can see, the function of the script is to make a request to the blog and see its response code:

Execution of the Python script showing HTTP response code

So, as seen in the code, the requests library is being called in a relative way:

Relative import of the requests library in the code

We’re going to take advantage of this to execute a Library Hijacking. The first thing is to check the path that python3 follows, we can do this with the sys library:

Visualization of Python's sys.path showing search paths

If we notice, the first place where Python checks by default for the existence of the library is in '', this means the current path. So we’ll simply create a file called requests.py in the current path:

Creation of malicious requests.py file for hijacking

This way, if we execute the script:

Successful exploitation of Library Hijacking executing malicious code

We manage to execute the command we’ve specified, in this case, a shell.

Be careful, in this case, we don’t apply the SUID privilege to Python, since being a script, it interferes with the security layer of the SUID permission itself:

Explanation of why SUID doesn't work with interpreted scripts

SUID doesn’t work in bash - Stack Overflow

However, we could take advantage of it to become root if for example we have sudo privileges over the execution of the script.