Welcome to part 2 of the buffer overflow series. In this blog, we will see the exploitation of buffer overflow vulnerability in detailed steps. Check out part one to learn the basics of overflow vulnerabilities.
The buffer overflow vulnerability occurs whenever data written to a buffer exceeds its size. The extra data can overflow into adjacent memory locations, potentially overwriting important data or executing malicious code.
Buffer overflows have been a major security concern for decades and are a common target for attackers. An attacker can use these attacks to gain unauthorized access to a system, execute malicious code, or steal sensitive data.
This blog will provide an overview of buffer overflow exploitation, including its causes and consequences. Furthermore, we will discuss the methods attackers use to exploit buffer overflows.
Understanding the basics is necessary before diving into exploitation and steps of buffer overflow.
To exploit buffer overflows at the machine level, we use assembly language. For attackers to execute malicious code, it is essential to understand how to control a program's execution flow.
To exploit buffer overflows, you need to understand a few basic concepts in assembly language:
Registers: Registers are fast, small storage locations in a processor for storing data that is being processed. Using buffer overflows, attackers can overwrite the contents of certain registers, allowing them to control the flow of execution.
EAX: The EAX register is a general-purpose register that holds the result of arithmetic operations and stores the address of the processed data. In buffer overflow exploitation, the EAX register stores the address of a pointer to the input buffer that contains the attacker's malicious code.
EDX: The EDX register is another general-purpose register often used with the EAX register. The EDX register stores the address of the fixed-size buffer that is being overflowed.
EBP: The EBP register is used as a base pointer to locate data on the stack. In buffer overflow exploitation, the EBP register can locate the return address stored on the stack, which the attacker will overwrite with the address of their malicious code.
ESP: The ESP register is used as a stack pointer to keep track of the top of the stack. In buffer overflow exploitation, the ESP register can locate the buffer that is being overflowed and identify the adjacent memory locations that will be overwritten.
EIP: The EIP register holds the address of the next instruction to be executed by the program. In buffer overflow exploitation, the attacker will attempt to overwrite the contents of the EIP register with the address of their malicious code.
Stack: In a program, the stack is a region of memory used to store data for function calls and return addresses. A buffer overflow can allow an attacker to hijack the flow of execution by overwriting data on the stack, including the return address.
When you call a function, a new frame pushes onto the top of the stack. This frame contains information about the function call, including the call's return address, any arguments passed to the function, and any local variables declared within the function.
Instructions: Assembly language instructions can move data, perform arithmetic operations, and jump to different program parts. An attacker can inject malicious code into a program using buffer overflows, which the processor can execute.
Several instructions can be involved in a buffer overflow vulnerability:
mov: This instruction copies a value from one memory location to another. A buffer overflow can occur if the destination buffer is not large enough to hold the data being copied.
cpy: Similar to mov, this instruction copies data from one memory location to another. Again, a buffer overflow can occur if the destination buffer is not large enough.
strcpy: This is a commonly used function in C that copies a null-terminated string from one buffer to another. A buffer overflow can occur if the destination buffer is not large enough.
memcpy: This is a C function that copies a specified number of bytes from one memory location to another. A buffer overflow can occur if the destination buffer is not large enough to hold the data being copied.
strncpy: This is a C function that copies a specified number of characters from one buffer to another. If the destination buffer is not large enough, the function will write null characters to the destination buffer to ensure that the string is null-terminated, but this can lead to a buffer overflow if the null characters overwrite adjacent memory locations.
sprintf: This is a C function that writes formatted output to a string buffer. A buffer overflow can occur if the destination buffer is not large enough.
vsprintf: This is a C function that writes formatted output to a string buffer, using a variable number of arguments. A buffer overflow can occur if the destination buffer is not large enough.
Potential Risks of Buffer Overflow
Buffer overflows can result in a wide range of security risks, including:
Arbitrary Code Execution: One of the most severe consequences of a buffer overflow is the ability of an attacker to execute arbitrary code with the permissions of the affected process. This can lead to a complete compromise of the system, including theft of sensitive information.
Denial of Service (DoS): A buffer overflow can cause a program to crash or hang, leading to a denial of service attack. This can result in temporary or permanent disruption of service and can also cause a chain reaction that spreads to other systems and services, potentially resulting in widespread outages.
Information Leakage: A buffer overflow can allow an attacker to access sensitive information, such as passwords, encryption keys, or confidential data, stored in the affected process's memory.
Elevation of Privilege: A buffer overflow can allow an attacker to gain elevated privileges on the affected system, potentially bypassing security controls and accessing sensitive systems and data.
General Exploitation Steps
Discovery: Identifying the vulnerability is the first step in exploiting a buffer overflow. An attacker can do this through manual code review, automated vulnerability scanning, or other means.
Craft the payload: Once the vulnerability has been identified, the attacker must craft a payload that will overwrite the buffer and redirect the program's execution flow to the attacker's code. An attacker must carefully construct this payload to bypass any security features such as ASLR or DEP.
Injection: The payload is then injected into the buffer, usually through a network-based attack vector such as a network packet or a web request.
Triggering: The attacker must then trigger the buffer overflow condition, causing the program to write the payload to the buffer and overwrite the adjacent memory locations.
Execution: Once the payload has been injected and the buffer overflow has been triggered, the attacker's code is executed, allowing them to take control of the program and execute their desired actions.
Now, We will be exploiting Windows based buffer-overflow. Here are a few prerequisites for the same.
Windows 10/Windows XP
Vulnerable Software Named R GUI
Windows-Based Buffer Overflow Example
We will be covering the following 6 steps in detail for buffer overflow:
- Finding Offset
- Finding Bad Characters
- Finding Vulnerable Modules
- Shellcode generation
In buffer overflow exploitation, fuzzing discovers vulnerabilities in software. The basic idea behind fuzzing is to send many malformed or unexpected inputs to a software program to identify input validation flaws that could lead to security vulnerabilities, such as buffer overflows.
- Generation of test inputs: The attacker then generates many malformed or unexpected inputs, known as "fuzz inputs." These inputs stress the software and expose any input validation flaws.
- Injection of test inputs: The fuzz inputs are sent to the software program through a network-based attack vector or by running the software with the fuzz inputs as input data.
- Monitoring: The software's behavior is monitored during the fuzzing process to identify any crashes or unexpected results. Any crashes or unexpected results are analyzed to determine if a security vulnerability, such as a buffer overflow, caused them.
A) Checking for vulnerability
Open Python interceptor and run the following command to generate inputs.
B) Copy the generated input and paste it into Input Field.
C)Click on OK, and the application will crash.
What is an offset?
In computer science, offsets are the positions of values within data structures, such as arrays, strings, or memory buffers. Offsets indicate how far a value is from the beginning of a data structure.
Regarding memory buffers, the offset refers to the position within the buffer where a particular value or piece of data is stored. For example, in a buffer of 100 bytes, an offset of 50 would indicate that a specific value is 50 bytes from the start of the buffer.
The offset may determine the location of an error within a buffer and access and manipulate data within buffers. Additionally, offsets can determine the location of malicious code if a buffer overflow occurs, allowing an attacker to control the flow of the program's execution.
Here we aim to control EIP as it stores the next instruction to execute; we will use an immunity debugger.
The immunity debugger will allow us to view the contents of registers at the time of the crash.
A) Attach a vulnerable file to Immunity Debugger by going to File>Open Vulnerable Application(32bit)
B) At First application will be opened in paused mode, so click on the Play button at the top. It will load the application into the immunity debugger and start.
We will again give large input to our vulnerable application and observe it in the immunity debugger.
As we can see, ESP and EIP registers are overwritten, and our vulnerable application crashed with an error access violation.
Now, we have to understand how much input we should give to our program to control our EIP register. For that, we can use the Metasploit framework.
For that, we need two ruby scripts given below.
It will create a payload, and after inputting in a vulnerable application attached to the immunity debugger, it will give us an offset value.
This script will match the value of the offset and will confirm the location.
A) Run pattern create
B) We give this generated input to vulnerable applications and observe it in the immunity debugger.
C)Observe the application and catch EIP register value.
EIP value: 6A41376A
D)Run pattern offset script and give EIP value.
E) Now we have to recheck our finding
F) Entering input in vulnerable applications.
G) Observing the application's EIP value.
It is nothing but 3 C's in Hexadecimal format. It means we have control over EIP register values.
What are bad characters?
In buffer overflows, "bad characters" are certain characters in input data that cause problems when present in the data used to overflow a buffer. These characters can cause the program's execution to deviate from the intended path and disrupt the execution of the payload to be injected into the vulnerable buffer.
When exploiting a buffer overflow vulnerability, carefully crafting the payload data is often necessary to avoid bad characters and ensure the payload executes correctly. This requires understanding the target system and the data used to exploit the vulnerability.
Here are some examples of characters that are commonly considered bad characters in buffer overflow exploitation:
Null bytes (ASCII value 0): These characters are often used to terminate strings in C and other programming languages and can cause problems when used in buffer overflow payloads.
Newline characters (ASCII value 10): These characters are often used as line separators in text files and can cause problems when used in buffer overflow payloads.
Carriage return characters (ASCII value 13): These characters are often used to separate lines in text files and can cause problems when used in buffer overflow payloads.
Non-printable characters (ASCII values 0-31): These characters can cause problems with output formatting or string manipulation.
Binary data: Some payloads may contain binary data, and characters within this binary data may be interpreted as bad characters.
- 00 for NULL
- 0A for Line Feed n
- 0D for Carriage Return r
- FF for Form Feed f
Finding Vulnerable Modules
It's a crucial step. After finding EIP value, we have to find a vulnerable DLL file that gets loaded when our R GUI application starts. Some DLL files don't have protection from buffer overflow attacks. We will find such DLL files using a tool named Mona.
1) Download Mona tool and copy Mona.py into \Immunity Debugger\PyCommands directory.
2)Now, let's fire up the immunity debugger with our vulnerable application again!
3)Input the following command to the command line in Immunity Debugger:
It will list all the dll files currently in use and their safety flags.
4)Then we will choose R.dll file, which is used by our vulnerable application and doesn't have any protection.
Finding OP code for JMP ESP
Now we will find the address pushed on the stack when R.dll is called in the application. For that, we have to run the following command:
!mona find -s "\xff\xe4" -m R.dll
In our case address is:
Building exploit to execute a command on a windows machine
We can build exploit code that will execute the command on windows machines when we put input in vulnerable applications.
So for that, let's quickly fire up kali console and type:
msfvenom -a x86 — platform Windows -p windows/exec cmd=notepad.exe -e x86/alpha_upper -b ‘\x00’ -f c
What is MSFvenom?
MSFvenom is a payload generator tool that is part of the Metasploit framework. The Metasploit framework is an open-source toolkit for developing and executing exploitation code.
MSFvenom creates and encodes payloads that attackers can integrate into exploit modules within the Metasploit framework. These payloads can be used to execute arbitrary code on a target system and for various purposes, such as establishing a reverse shell, creating a bind shell, or running a meterpreter session.
It supports a wide range of platforms and architectures and allows for creation of payloads designed to evade anti-virus software. The tool integrates with the Metasploit framework, providing a powerful and flexible platform for penetration testing and security research.
MSFvenom is a critical tool within the Metasploit framework, allowing the ability to generate custom payloads to exploit vulnerabilities in target systems.
Command: msfvenom -a x86 — platform Windows -p windows/exec cmd=notepad.exe -e x86/alpha_upper -b ‘\x00’ -f c
We must merge our exploitation script and a few NOP sled characters to work it properly.
What is NOP sled characters?
A NOP (No Operation) sled is a sequence of NOP instructions in machine code that does nothing when executed. In a buffer overflow attack, a NOP sled is a filler between the injected malicious payload and the return address the attacker wants to overwrite in the vulnerable program's stack.
The purpose of a NOP sled is to provide a predictable and controllable path for the program's execution to reach the injected malicious payload. When a buffer overflow occurs, the excess data written to the buffer can overwrite adjacent data on the stack, including the return address. The attacker can use a NOP sled to increase the chances that the overwritten return address will point to the start of the NOP sled, leading to the execution of the malicious payload.
Here are some examples of NOP sleds for different architectures:
x86 (32-bit): The x86 architecture uses the 0x90 instruction to represent a NOP. A NOP sled for x86 can be represented as a sequence of 0x90 instructions.
x86-64 (64-bit): The x86-64 architecture also uses the 0x90 instruction to represent a NOP. A NOP sled for x86-64 can be represented as a sequence of 0x90 instructions.
ARM (32-bit): The ARM architecture uses the 0x01 instruction to represent a NOP. A NOP sled for ARM can be represented as a sequence of 0x01 instructions.
Final Code Looks Like This
Run this exploit in kali Linux and it will generate malicious input which can execute command if application is vulnerable to buffer overflow.
Now input shellcode in vulnerable application and observe the result.
Reverse shell using buffer overflow
Prerequisites for Demonstration
- Vulnerable application: dostackbufferoverflowgood.exe
- Testing/Analysis Machine: Microsoft Windows 10
- Attacker Machine: Kali Linux
- Debugger used: Immunity Debugger
A) Open the application and run Nmap scan on windows IP address
B) To application via Netcat to understand functionality.
D)Running Fuzzer and observing crash.
E) Observing crash and ESP register value in immunity debugger.
F) Creating payload for offset value.
G) Script for finding offset value.
H) Observing offset value in immunity debugger.
I)Generating bad characters by script.
J) Observing bad characters in registers.
K) Finding JMP ESP via Mona in Immunity Debugger.
L) Got JMP ESP address.
M) Generating Reverse Shell Payload via MSFvenom.
N) Start Netcat on 4444 port and run the exploit with combining crashing value+ JMP ESP + NOPs + Shellcode.
O) Observing Netcat connection!
Is Buffer Overflow still a concern?
Buffer overflows continue to be a problem in the modern era. One recent example is the remote code execution vulnerability (CVE-2022-0601) discovered in Microsoft Windows CryptoAPI (Crypt32.dll) in January 2022. This vulnerability was due to a buffer overflow in how the Windows CryptoAPI handled Elliptic Curve Cryptography (ECC) certificates. An attacker could exploit this vulnerability by crafting a malicious certificate and convincing a user to install it on their system, allowing the attacker to execute arbitrary code with the user's permissions.
Another example is the heap buffer overflow vulnerability (CVE-2022-0796) in the OpenSSL library in March 2022. This vulnerability affected multiple platforms, including Linux, Windows, and macOS, and could allow an attacker to execute arbitrary code with the permissions of the user who is running the vulnerable software.
Buffer overflow exploitation is a serious threat to the security of software systems, and it's essential for developers to be aware of the dangers of buffer overflows and to take the necessary precautions to protect against these types of attacks. This can include using secure coding practices, canary values to detect buffer overflows, and various mitigation techniques such as stack protection and address space layout randomization (ASLR). By being proactive about security, developers can help protect their software systems against buffer overflow exploitation and other security threats.
Buffer Overflow Labs