While there have been numerous articles on RCE or Remote Code Execution vulnerabilities over the last three years, we have yet to see this technique succeed on a large scale. But don’t be misled into thinking it’s some obscure or esoteric technique; nothing could be further from the truth. Today’s topic will be the fundamentals of RCE exploits that have, to put it mildly, worked for the masses. I’d like to start by saying that you don’t need advanced skills to get your RCE code to work today.
The only skills I will assume you will need to have mastered are writing basic shellcode and the ability to navigate your environment in a shell. Also, you will need some basic C programming skills. I will go over many ideas that even the most experienced developers tend to miss. So without any further ado, let’s get started!
Table of Contents
What is Remote Code Execution?
There is a lot of hype surrounding RCE techniques nowadays, but for the general user, this is just a way to run arbitrary code or at least run shellcode from external sources. One major aspect of code execution that usually gets overlooked is the return of the shellcode execution. The general idea is to get user input and then write the code into memory and return back. But if the shellcode can return, and the user is not being filtered at such time, we can control a lot of possibilities, such as:
We can control the network connectivity; We can control the user account; We can manipulate the execution of an entire process; We can control where a thread runs based on what we decide to put in memory; We can even inject a new process or execute a file we write in memory.
So basically, the goal is to not only get the user to run code that we have written, but the user must also allow for this code to run unverified.
If we need to run a shellcode or a script that is encoded/encrypted, then we need to somehow decode or un-encode the shellcode. We can use a tool such as msfpescan to decode shellcode, or we can use some sort of encoding/decoding algorithm.
Also, note that when running shellcode on x86 architecture, the location of the stack pointer plays a big role in determining where the code will be executed. You can find the stack pointer by reading the EBP register and subtracting it from ESP. This will give you the location of EBP relative to ESP, so you can use this information to determine where in memory your shellcode is located.
The stack pointer is located at the top of the stack, so when we subtract EBP from ESP, we will get a location that points to a location in memory that contains the start of our shellcode. We can then use this information to determine where in memory we want our payload to be executed.
Our Goal — How To Read Memory?
So, here is the basic process that most people do not understand. This is how we begin in this area — RCE is a process of determining where the stack pointer or ESP is located in memory. Once we have this information, we can start reading memory to find our shellcode.
- We read the address of the data that we want to alter.
- We use a write call to our data area (this is the data we want to change).
- We read the value of our data area again. This is called a race condition because, at this point, only one process has access to the data in memory.
- We can then alter our payload with whatever new values we have chosen.
The idea behind this is that we can use a write call to change the address of our stack pointer. We then read from this new location and find our shellcode, which we can alter. This gives us the ability to control where our code executes in memory.
How To Generate A Stack-Pointer Overflow In C Without Assembly
Sometimes you may need to generate a stack-pointer overflow without using assembly. This is often the case when you’re working with a language like C or Java, and there is no native support for assembly. In this article, we’ll walk through how you can generate a stack-pointer overflow in C without assembly so that you can use it as part of your exploit development process.
What Is A Stack-Pointer Overflow?
Stack-pointer overflows are a type of buffer overflow in which the memory addresses pointed to by the stack pointer are overwritten. This results in an out-of-bounds write, which can overwrite the return address on the stack and cause a program crash or allow for exploitation.
Stack-pointer overflows can occur when a program attempts to use more memory than it is allocated or when it attempts to use more space than is available at the end of an array. The same thing happens when you have a function that lets you pass more arguments than you declared or if you have too many local variables declared in a function (this will also result in memory corruption).
As an example, let’s say we have a function that takes three arguments: int foo(int arg1, int arg2, int arg3); In this case, we’d have our stack look something like this:
[arg1][arg2][arg3][return address]
When we put all this together, what happens if we call foo with six arguments? We’ll get something like this:
[arg1][arg2][arg3][ arg4][arg5][arg6][return address]
This causes our stack to get messed up, which can result in things like memory corruption.
Let’s walk through an example:
Say we have our program written in C. Our code looks like this:
int main() { }
Now let’s say we want to overwrite the value of esp with 0x41414141. We can do this by writing out a shellcode into memory and then overwriting esp with the address of our shellcode:
void main () { char buffer[256]; memset(buffer, 0x41, 256); memcpy(buffer + 8, "AAAABBBBCCCC", 4); buffer[8] = 0; fwrite(buffer, 1, 256, stdout); } // end main
This will print out “AAAAAAAAAAAAA” on stdout. The reason it prints out “A” is that we’ve overwritten the first byte of our buffer with ‘A’, which is ASCII for ‘A’.
But what if we wanted to print out “AAAABBBBCCCC”?
We need to overwrite the buffer with something else first. This can be done by overwriting esp with a NOP sled:
void main () { char buffer[256]; memset(buffer, 0x41, 256); memcpy(buffer + 8, "AAAA", 4); buffer[8] = 0; fwrite(buffer, 1, 256, stdout); } // end main
5 Best Ways To Prevent Remote Code Execution Vulnerability Exploitation
The best way to prevent remote code execution vulnerability exploitation is to use proper input validation and output encoding. If an application accepts user-provided data, it should be validated before being processed further by the application. This can be done by escaping the user input, validating it against a regular expression, and then encoding it using base64 or URL-encoding. The output of an application should also be encoded to prevent XSS attacks.
Beyond these basic mitigations, there are a few things that can be done to prevent remote code execution vulnerability exploitation.
1) Use a Firewall
A firewall can be a real lifesaver when it comes to preventing remote code execution vulnerability exploitation. A firewall is a software program or hardware device that protects your computer from intruders by filtering traffic between your computer and the Internet. It allows only authorized traffic through while blocking unauthorized traffic.
A firewall can block attacks and prevent intruders from accessing your system. A firewall can also protect against Denial of Service (DoS) attacks, which are attempts to make a network resource unavailable to its intended users.
If you’re using Windows OS, your operating system already has a built-in firewall called “Windows Firewall.” You can find it in the Control Panel under Security > Windows Firewall. If you’re using Linux or Mac OS X, you’ll need to install third-party firewalls.
2) Keep Your OS And Every Essential 3rd Application Updated
When you are using a web application, you need to ensure that your operating system and all the applications that run on it are updated. If you don’t, you could easily be vulnerable to an attack that exploits a remote code execution vulnerability.
This means that if there’s a new update available for your operating system or any other application that is essential to your business operations (e.g., Microsoft Office), then you should make sure that you install it as soon as possible so that any security vulnerabilities can be fixed before they are exploited by hackers who want to gain access to your company’s network.
3) Employ Server Monitoring Tools
Monitoring tools like New Relic, Datadog, and AppDynamics are the best way to prevent remote code execution vulnerabilities from being exploited. These tools will help you identify when a new process is created on your server and whether or not it’s related to any of your applications. If you’re not using one of these tools, reach out to your hosting provider for assistance with setting up access.
4) Avoid using Untrusted Input in the File Pathname
This is a security risk that’s easy to avoid, but it’s very important to remember. Remote code execution occurs when a hacker is able to use a file that you’ve opened or saved on your computer and then run their own code on your computer. For example, if you have an executable file (such as a .exe file) that you downloaded from the Internet and saved to your computer and then opened it after downloading it, this would be considered remote code execution vulnerability exploitation
You should never download files from untrusted sources such as emails or websites unless you know for sure what they are and why they’re there. The best way to avoid remote code execution vulnerability exploitation is by being aware of what files you’re downloading and where they came from. You should never download a file that you don’t know or trust.
5) Use a Layered Approach to Security
When it comes to preventing remote code execution vulnerability exploitation, you need to think like a hacker. You need to know what they are looking for and how they will try to exploit your system. This is why we recommend using layers of security that work together to protect your website from attacks.
The first layer of security is an intrusion detection system (IDS). An IDS can monitor traffic on your network and detect any unusual activity that may indicate an attack attempt. It will send alerts when it detects suspicious activity so that you can take action quickly if necessary.
The second layer of security is a firewall. A firewall protects your network from unauthorized access by keeping unauthorized users out while allowing legitimate users inside. If a hacker tries to gain access through your firewall, they will find it difficult because they must interact with multiple layers before getting into the system.
The third layer of security is antivirus software. Antivirus software monitors all incoming and outgoing files on your server and compares them against known virus signatures before allowing them into the system or uploading them onto the web server, where they could infect visitors’ computers if they were maliciously infected with a virus or Trojan horse program.
The fourth layer of security is data encryption. Data encryption uses a mathematical algorithm to convert information into a series of numbers that are meaningless to anyone except the person who holds the key to decode them. This ensures that your data remains secure even if someone were to gain access to your server through one or more of the other layers of security.
Final Verdict
RCE or Remote Code Execution is one of the most frightening vulnerabilities that can occur within a software product. Hopefully, this guide has helped you understand RCE and what it means for your business. It is important to be aware of these types of vulnerabilities and how they can affect the security of your systems.