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 his ultimate goal of assuming control over the machine.

SOFTWARE VS HARDWARE DEFENCES OVER TIME.

1990s.

Attackers

During the early days the attacks were straight forward, dubbed code injection attacks. The attacker simply needed to provide his 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. This included several variants of flow control protections such as stack canaries, SEH protections and heap integrity validators. All of which were meant to mitigate control flow hijacking. In 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 2 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 his injected code.

2000s.

Attackers

To bypass this hardware enforced mitigation a new concept had to be invented, dubbed code reuse attacks. Rather than delivering code within a payload, they simply pieced together existing snippets of code (i.e. “gadgets”) of the attacked application to perform the same logic that their designated code would have carried out. In other words, code reuse attacks abuse existing code to assemble new logic. For instance, short snippets of codes ending with RET (usually function epilogues) is called Return Oriented Programing.

Defenders

Naturally, numerous software level defenses were proposed to counter code reuse attacks. This includes several variants of techniques which randomize the program’s memory layout in order to prevent the attacker from utilizing gadgets at predictable locations. Additionally, the notion of control-flow integrity (CFI) emerged, which aims to explicitly validate each control flow event issued by the processor. These software level solutions have since been shown to have various weaknesses and restrictions, in both design and implementation. Meanwhile, hardware vendors are currently working on solutions (e.g. Intel’s Control-flow Enforcement Technology or CET). CET is a CFI implementation at the hardware level that tracks control flow instructions in order to detect any deviation from the intended programs execution flow. It is planned to be released in future Intel chips when ready, and it is one of the latest in a series of hardware level mitigations to be introduced in Intel CPUs over the past 20 years

Today.

Attackers

During the early days the attacks were straight forward, dubbed code injection attacks. The attacker simply needed to provide his 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. This included several variants of flow control protections such as stack canaries, SEH protections and heap integrity validators. All of which were meant to mitigate control flow hijacking. In 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 2 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 his injected code.

What next?

In this cat-and-mouse game, it has become apparent that hardware or software-only defenses are no longer sufficient. Hardware level defenses certainly raise the bar as they require the development of a new attack concept in order to be circumvented.
Vendors ability to effectively and timely react to advancement is severely limited – the costs of patching software throughout millions of end-devices are extremely high, and in the case of hardware mitigations – is usually not even an option (i.e. the time between in-the-wild ROP attacks and CET’s delivery is roughly a decade).

Software defenses are far faster to develop and implement, but they are inherently myopic due to their nature of being part of the system that they defend.
That’s why defense today needs to extract the best of both hardware and software, with technology that provides hardware level code visibility but in a software solution that is fast and easy to update. It is only with this combination that the defense will remain robust against the current types of attacks, while having the flexibility to quickly evolve with new approaches.

Sources.

  • http://hick.org/~mmiller/presentations/misc/exploitation_techniques_and_mitigations_on_windows.pdf
  • AMD. AMD 64 and Enhanced Virus Protection.
  • 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.
  • https://www.usenix.org/legacy/event/sec09/tech/slides/sotirov.pdf
  • http://ieeexplore.ieee.org/document/6956588/
  • https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf
  • http://syssec.rub.de/media/emma/veroeffentlichungen/2015/03/28/COOP-Oakland15.pdf
  • https://www.endgame.com/blog/technical-blog/disarming-control-flow-guard-using-advanced-code-reuse-attacks
  • https://msdn.microsoft.com/en-us/library/windows/desktop/mt637065(v=vs.85).aspx