Under the EDR Radar: A Deep Dive into Binary Exploitation

By: Cymulate Research Lab

Last Updated: December 18, 2024

image

Businesses now face a relentless number of daily cyber threats, and in order to combat them, an organization must position themselves on the offensive and start thinking like an adversary themselves. They must invest in comprehensive security validation technology and resources and gain an understanding of go-to binary exploitation techniques. Understanding binary exploitation techniques is not just about identifying vulnerabilities; it’s about preemptively closing the gaps that malicious actors seek out.

Exploitation techniques are methods used by cyber attackers to target vulnerabilities in software, systems or networks to gain unauthorized access, execute arbitrary code, steal data and disrupt service. Exploitation techniques are particularly significant when validating endpoint detection and response (EDR) tools that claim preemptive protection or at least detection. EDR systems monitor endpoints to identify threats and behavioral analysis, allowing for early detection and pattern identification of malicious activities.

Embedding these practices into your organization’s security strategy can not only help safeguard valuable assets, maintain customer trust and uphold reputation in an increasingly insecure world. By becoming familiar with the most popular binary exploitation techniques applied by threat actors, your organization can stay a step ahead and strengthen its security posture.

Many EDR vendors claim to provide protection against known exploitation techniques, such as buffer overflow or format string. Proving it is another story. Cymulate put theories to the test by conducting experiments on both Windows and Linux platforms. By creating purposefully vulnerable programs, each containing a specific vulnerability, we were able to develop an exploit for each one.

  1. Buffer overflow – A buffer overflow is a vulnerability where input data exceeds the allocated storage space, corrupting or controlling the program’s execution flow. By feeding a crafted input, it changes where the program goes next in its execution by overwriting the return address of the current function. Buffer overflows can be exploited by attackers to execute arbitrary code, gain unauthorized access, or cause other malicious behavior.
  2. Format string – A format string vulnerability, which happens when input data is improperly processed, can lead to unauthorized memory access or alteration. By sending a specially crafted string containing format specifiers, the exploit manipulates the program’s memory to change its execution flow. The crafted input will contain flag characters of format string (“%d”, “%s, “%x”, “%p”, “%n”).
  3. Integer underflow – An integer underflow vulnerability occurs when a mathematical operation results in a value smaller than the minimum representable value for an integer type, often leading to unexpected behavior or security vulnerabilities. In our example, we will submit a negative number to manipulate the program’s logic, causing an unexpected increase in a critical control variable.
    For instance, the range for an int is: “-2,147,483,648 to 2,147,483,647.”
    The maximum value for an unsigned int is: “4,294,967,295.”
    When the value “-1” is submitted in an unsigned int representation, it is represented as “4,294,967,295”—the maximum size of an int.
  4. Race condition – A race condition vulnerability occurs when the timing or sequence of events in a multithreaded or asynchronous system can be manipulated by attackers to compromise security. In exploitation, attackers can take advantage of race conditions to manipulate the behavior of a program or system in unintended ways.
    In our example, the exploit targeting a race condition vulnerability involves the manipulation of a file’s contents between the validation and execution phases. The vulnerable program creates and checks a dummy executable’s hash, intending to execute it if the hash matches a predetermined value. The exploit operates by repeatedly replacing the dummy executable with a malicious one after the hash check, hoping to do so within the window before the file’s execution.
    This timing discrepancy between checking and running the executable allows the exploit to insert malicious code. Successful exploitation is marked by the program executing the replaced file, demonstrating the race condition where the security check becomes ineffective due to the temporal gap, allowing unauthorized code execution.
  5. Heap overflow – A heap overflow vulnerability occurs when a program writes more data to a heap-allocated memory buffer than it can hold. This can lead to overwriting adjacent memory areas, potentially causing crashes, corruption or security breaches. Attackers can then exploit heap overflows to execute arbitrary code or manipulate the program’s control flow.
  6. Use after free – A use after free (UAF) vulnerability occurs when a program accesses memory after it has already been freed or deallocated, leading to unexpected behavior or a crash.
    This type of vulnerability unfolds as follows:
    First, the program allocates memory to a pointer, which is then used for various operations.
    Later, the memory is deallocated, but the pointer isn’t cleared or reassigned; it still points to the address of the memory that was originally allocated. This dangling pointer can then mistakenly be used again. When this deallocated memory is accessed through the old pointer, the program might behave unpredictably because the memory might now contain different data or be used by another part of the program.
    By exploiting this vulnerability, an attacker can manipulate the program’s execution flow and potentially execute arbitrary code. This manipulation occurs because the attacker can influence what data is stored at the previously freed memory location, gaining control over the program’s operation.

Buffer Overflow – POC Exploitation Test

The most common type of vulnerability is the buffer overflow. Just as real life can be unpredictable, our vulnerable software provided transparency other vendors often can’t match. We designed the privilege of control with a function specifically intended to execute shellcode. This test code has specific flags that simplify the exploitation process, all of which the modifications are intended to test whether the EDR will alert on any memory corruptions as expected.

To begin testing, we wrote a simple C program as shown below:

Buffer Overflow - POC Exploitation Test
Buffer Overflow - POC Exploitation Test

To read into the exploit without limitation, we used the highly vulnerable ‘gets’ method. Along with undefined behavior and deprecation, the ‘gets’ function does not perform any bounds checking on the size of the buffer provided, meaning that if the input exceeds the allocated size of the buffer, it will overwrite adjacent memory locations, leading to buffer overflow.

When we put the buffer overflow to the test in the ‘vuln’ function, with a buffer of size 8, we can overwrite the return address of the ‘vuln’ function, redirecting the program to execute the ‘win’ function instead of the ‘lose.’ The size of the buffer was a random choice with the goal of simply overflowing the buffer by providing more data than it could handle.

This simple buffer overflow exploit aims to execute shellcode, which could be anything, however, in our experiment we used shellcode that executes the command ‘/bin/cat/etc/passwd’. The corresponding Windows version of this code features a customized ‘win’ function that runs on Windows machines, where the shellcode executes ‘calc.exe.’

How to Spot a Successful Binary Exploitation

The command shown below “/bin/cat /etc/passwd” means that the exploitation was successful. But how does a vendor know what to look for? The command ran at the end represents the actual impact of the software exploitation. We expect EDR vendors to be able to detect exploit attempts, as many claim to do. For example, if they recognize memory corruption, they should alert their security team about it. Detection of the impact should not be what is solely relied upon.

How to Spot a Successful Binary Exploitation

Checking Against EDRs

In addition to the experiment we ran, there are other methods used to determine if exploitation techniques are on their way to being successful.

  1. Intrusion detection system (IDS): These systems monitor network traffic and system behavior for signs of suspicious activity.
  2. Regular security assessments: Conducting penetration tests and security audits to simulate attacks can reveal vulnerabilities that could be exploited.
  3. Incident reports: Analyzing security incidents can help identify patterns of exploitation.
  4. Post-incident analysis: After a security incident, forensic analysis can reveal how an attacker gained access, what techniques were used, and whether any successful exploitation occurred.
  5. Anomaly detection: With behavioral analysis, machine learning algorithms can analyze normal user behavior and flag deviations that may indicate exploitation.

What Happens When a Trigger Alert Fails?

Data can become easily manipulated by an attacker in the early stages of exploitation, if and when a trigger alert fails. Attackers can maneuver through software without detection, potentially leading to data breaches or unauthorized access. Even in the instance that shellcode execution is caught, undetected exploit attempts could allow attackers to bypass defenses, exfiltrate data or establish continuous access.

Signs of potential alert failure include missing early-stage exploit attempts, like memory corruption and only detecting shellcode execution. An over-reliance on impact detection increases the risk of missing attacks.

igns of potential alert failure include missing early-stage exploit attempts, like memory corruption and only detecting shellcode execution.

During our testing, we discovered that we were within the shellcode when the EDR issued an alert. However, the alert was not triggered by the buffer overflow exploit itself, but rather matched a predefined rule set for detecting malicious shellcode. This finding indicates that with some obfuscation of the shellcode, it could be possible to bypass the EDR’s defenses and execute our shellcode on the vulnerable program.

How to Improve Prevention and Detection

Security teams can implement a variety of prevention strategies that would enhance the prevention and detection of exploitation techniques. One of the reasons that these types of attacks are challenging is due to being low-level; there isn’t much that security teams can do directly. Teams must ensure that all software within the organization is up to date, since most exploits usually occur on legacy or unpatched software.

Other strategies might include:

  • Code review and secure coding practices: This encourages developers to follow secure coding guidelines to minimize vulnerabilities, such as buffer overflows and UAF errors.
  • Input validation and sanitization: By implementing strict validation, this helps ensure that data received by the application meets expected formats and constraints.
  • Access controls and least privilege: Implementing robust access controls to limit user privileges based on the principle of least privilege and regularly auditing user permissions to ensure compliance with security policies.
  • Intrusion detection and prevention systems (IDPS): Deploying an IDPS to monitor network traffic for suspicious patterns that may indicate exploitation attempts and use anomaly-based detection to identify deviations from normal behavior.

Key Takeaways

This blog examined claims made by EDR vendors regarding their ability to protect against various exploit techniques, such as buffer overflows and UAF. Through a series of experiments conducted on both Windows and Linux platforms, we successfully demonstrated how these protections are not as foolproof as we would like to believe or is advertised.

By creating and exploiting vulnerabilities across six popular binary exploitation techniques, our findings shows that while EDR’s did trigger alerts during the shellcode execution phase, they failed to detect the initial exploitation attempts, such as the buffer overflow itself. Leaving the early phases of exploitation vulnerable to significant security threats without being detected.

To learn more about how Cymulate can help your security, SOC or MSSP team stay ahead of potential threats, schedule a demo today.

Book a Demo
Subscribe