An Overview of the History of Software Exploitation Techniques & Modern Defenses

0xshlomil · February 22, 2018

As with any market where crime is lucrative, cybersecurity will always exist, and the more digital the world becomes, the more it will grow. This market is so dynamic because it follows a cat-and-mouse model where the defenders are continuously trying to catch up to the attackers. In this article, we’ll discuss how this has played out over the history of software exploitation techniques, which typically play a part in every major cyber attack, and what it means for how defensive technologies must be approached today.

The Fundamentals of Any Attack

The ultimate goal of an attacker is to gain unauthorized access to a target system in order to perform malicious operations. Malicious actions are performed by illegitimate code that was not intended by the developer of the exploited software. The malicious code typically arrives over regular communication channels, such as email, and once placed in the program memory, triggers pre-existing software flaws. By exploiting such flaws in an orchestrated and predictable fashion, the attacker achieves their ultimate goal of assuming control over the machine.


Software vs Hardware Defenses Over Time

1990s

Attackers

During the early days, the attacks were straightforward, dubbed code injection attacks. The attacker simply needed to provide their malicious input and trigger a pre-existing software flaw to affect the control flow of the program and divert the execution to the malicious input (i.e., shellcode).

Defenders

To counter code injection attacks, numerous software-level solutions were proposed. These included several variants of flow control protections such as stack canaries, SEH protections, and heap integrity validators, all aimed at mitigating control flow hijacking. Over time, techniques to bypass these mitigations were developed and made public knowledge. Around the same time, hardware vendors introduced a feature called Data Execution Prevention, implemented by the addition of the no-execute (NX) bit that creates an in-memory distinction between data and code. In this way, malicious code that is placed in program memory that serves as data (i.e., stack and heap regions) will fail to execute when the attacker triggers a vulnerability that diverts the execution flow to their injected code.


2000s

Attackers

To bypass this hardware-enforced mitigation, a new concept was invented: code reuse attacks. Rather than delivering code within a payload, attackers pieced together existing snippets of code (i.e., “gadgets”) in the attacked application to perform the same logic their designated code would have carried out. For example, short snippets of code ending with RET (usually function epilogues) are used in Return Oriented Programming (ROP).

Defenders

In response, numerous software-level defenses were proposed to counter code reuse attacks. These included techniques to randomize the program’s memory layout, preventing attackers from utilizing gadgets at predictable locations. The concept of control-flow integrity (CFI) also emerged, aiming to explicitly validate each control flow event issued by the processor. While these software solutions showed promise, they also revealed weaknesses in both design and implementation. Meanwhile, hardware vendors developed solutions such as Intel’s Control-flow Enforcement Technology (CET). CET is a hardware-level CFI implementation that tracks control flow instructions to detect deviations from the intended program execution flow.


Today

Attackers

The techniques used by attackers have evolved significantly, leveraging sophisticated code reuse attacks and exploiting weaknesses in both software and hardware defenses.

Defenders

Defense mechanisms today combine hardware and software solutions. Hardware-level defenses, like CET, raise the bar by requiring entirely new attack concepts for circumvention. However, they are slow to deploy due to the challenges of hardware patching and distribution. In contrast, software defenses are faster to develop and deploy but are inherently limited by being part of the system they defend.


What Next?

In this cat-and-mouse game, it has become apparent that hardware- or software-only defenses are no longer sufficient. Hardware defenses raise the bar but are costly and slow to update. Software defenses are faster to implement but limited by their integration into the system they protect.

Today’s defenses need to combine the best of both worlds: hardware-level code visibility in a software solution that is fast and easy to update. Only this combination can provide robust protection against current attacks while remaining flexible enough to evolve with emerging threats.


Sources

  1. Exploitation Techniques and Mitigations on Windows
  2. AMD. AMD 64 and Enhanced Virus Protection.
  3. Shacham, “The geometry of innocent flesh on the bone: Return-into-libc without function calls (on the x86),” in Proceedings of the 14th ACM conference on Computer and communications security. ACM, 2007, pp. 552–561.
  4. USENIX: Advanced Code Reuse Attacks
  5. Control-flow Enforcement Technology Preview
  6. COOP: Attacking Control Flow Integrity
  7. Disarming Control Flow Guard
  8. Microsoft: Control Flow Guard

Originally posted at https://perception-point.io/blog/hardware-vs-software-exploitation/

Twitter, Facebook