
Control-Flow Bending: On the Effectiveness of Control-Flow Integrity Nicolas Carlini, University of California, Berkeley; Antonio Barresi, ETH Zürich; Mathias Payer, Purdue University; David Wagner, University of California, Berkeley; Thomas R. Gross, ETH Zürich https://www.usenix.org/conference/usenixsecurity15/technical-sessions/presentation/carlini This paper is included in the Proceedings of the 24th USENIX Security Symposium August 12–14, 2015 • Washington, D.C. ISBN 978-1-939133-11-3 Open access to the Proceedings of the 24th USENIX Security Symposium is sponsored by USENIX Control-Flow Bending: On the Effectiveness of Control-Flow Integrity Nicolas Carlini Antonio Barresi Mathias Payer David Wagner UC Berkeley ETH Zurich Purdue University UC Berkeley Thomas R. Gross ETH Zurich Abstract Defenses that prevent the corruption stop the actual Control-Flow Integrity (CFI) is a defense which pre- memory corruption before it can do any harm to the pro- vents control-flow hijacking attacks. While recent re- gram (i.e., no attacker-controlled values are ever used search has shown that coarse-grained CFI does not stop out-of-context). Examples for prevent-the-corruption attacks, fine-grained CFI is believed to be secure. defenses are SoftBound [22], Data-Flow Integrity [6], We argue that assessing the effectiveness of practi- or Code-Pointer Integrity [18]. In contrast, prevent- cal CFI implementations is non-trivial and that common the-exploit defenses allow memory corruption to occur evaluation metrics fail to do so. We then evaluate fully- but protect the application from subsequent exploitation; precise static CFI — the most restrictive CFI policy that they try to survive or tolerate adversarial corruption of does not break functionality — and reveal limitations in memory. Examples for prevent-the-exploit defenses are its security. Using a generalization of non-control-data DEP [38] or stack canaries [10]. attacks which we call Control-Flow Bending (CFB), we Control-Flow Integrity (CFI) [1, 3, 12, 15, 27, 30, 31, show how an attacker can leverage a memory corruption 39, 41–44] is a promising stateless prevent-the-exploit vulnerability to achieve Turing-complete computation on defense mechanism that aims for complete protection memory using just calls to the standard library. We use against control-flow hijacking attacks under a threat this attack technique to evaluate fully-precise static CFI model with a powerful attacker that can read and write on six real binaries and show that in five out of six cases, into the process’s address space. CFI ensures that pro- powerful attacks are still possible. Our results suggest gram execution follows a valid path through the static that CFI may not be a reliable defense against memory Control-Flow Graph (CFG). Any deviation from the corruption vulnerabilities. CFG is a CFI violation, terminating the application. CFI We further evaluate shadow stacks in combination is not specific to any particular exploitation vector for with CFI and find that their presence for security is nec- control-flow hijacking. Rather, it enforces its policy on essary: deploying shadow stacks removes arbitrary code all indirect branch instructions. Therefore any attempt by execution capabilities of attackers in three of six cases. an attacker to alter the control-flow in an invalid manner will be detected, regardless of how the attacker changes 1 Introduction the target of the control-flow transfer instruction. CFI is often coupled with a protected shadow stack, Attacking software systems by exploiting memory- which ensures that each return statement matches the corruption vulnerabilities is one of the most common corresponding call and thereby prevents an attacker from attack methods today according to the list of Common tampering with return addresses. While the foundational Vulnerabilities and Exposures. To counter these threats, work [1, 15] included a shadow stack as part of CFI, several hardening techniques have been widely adopted, some more recent research has explored variants of CFI including ASLR [29], DEP [38], and stack canaries [10]. that omit the shadow stack for better performance [9]. Each has limitations: stack canaries protect only against Whereas conformance to the CFG is a stateless policy, contiguous overwrites of the stack, DEP protects against shadow stacks are inherently dynamic and are more pre- code injection but not against code reuse, and ASLR does cise than any static policy can be with respect to returns. not protect against information leakage. Many prior attacks on CFI have focused on attacking a We classify defense mechanisms into two broad cat- weak or suboptimal implementation of CFI. Our focus is egories: prevent-the-corruption and prevent-the-exploit. on evaluating the effectiveness of CFI in its best achiev- USENIX Association 24th USENIX Security Symposium 161 able form, instead of artifacts of some (possibly weak) 2 Background and software attacks CFI implementation. We define fully-precise static CFI as the best achievable CFI policy as follows: a branch Over the past few decades, one of the most common at- from one instruction to another is allowed if and only tack vectors has been exploitation of memory corruption if some benign execution makes that same control-flow within programs written in memory-unsafe languages.In transfer. Such a policy could be imagined as taking any response, operating systems and compilers have started CFG over-approximation and removing edges until re- to support countermeasures against specific exploitation moving additional edges would break functionality. vectors and vulnerability types, but current hardening Thus, fully-precise static CFI is the most restrictive techniques are still unable to stop all attacks. We briefly stateless CFI policy that still allows the program to run as provide an overview of these attacks; more information intended. Both coarse-grained and fine-grained CFI are may be found elsewhere [37]. less precise than fully-precise static CFI, because they both over-approximate the set of valid targets for each 2.1 Control-Flow Hijacking indirect transfer (though to a different degree). In con- trast, fully-precise static CFI involves no approximation One way to exploit a memory corruption bug involves by definition. We acknowledge that fully-precise static hijacking control flow to execute attacker-supplied or CFI might be stricter than anything that can be prac- already-existing code in an application’s address space. tically implemented, but this makes any attacks all the These methods leverage the memory corruption bug to more meaningful: our results help us understand funda- change the target of an indirect branch instruction (ret, mental limits on the effectiveness of the strongest possi- jmp *, or call *). By doing so, an attacker can completely ble CFI policy. control the next instructions to execute. Through several methods of evaluation, we argue that fully-precise static CFI is neither completely broken (as 2.2 Code-Reuse Attacks most coarse-grained defenses are) nor totally secure. We explore what CFI can and cannot prevent, and hope that Data Execution Prevention (DEP) prevents executing this will stimulate a broader discussion about ways to fur- attacker-injected code. However, redirecting control- ther strengthen CFI. flow to already-existing executable code in memory re- We evaluate the security of fully-precise static CFI mains feasible. One technique, return-to-libc [25, 36], both with and without shadow stacks. Recent research reuses existing functions in the address space of the vul- achieves better performance by omitting the shadow nerable process. Runtime libraries (such as libc) often stack in favor of a static policy on return statements. We provide powerful functions, e.g., wrapper functions for still call it fully-precise static CFI when we have added most system calls. One example is libc’s system() a shadow stack, because the shadow stack is orthogonal. function, which allows the attacker to execute shell com- This does not change the fact that the CFI policy is static. mands. Code-reuse attacks are possible when attacker- CFI works by preventing an attacker from deviating needed code is already available in the address space of from the control-flow graph. Our attacks do not involve a vulnerable process. breaking the CFI mechanism itself: we even assume the mechanism is implemented perfectly to its fullest extent. 2.3 Return Oriented Programming Rather, our analysis demonstrates that an attacker can still create exploits for most real applications, without Return Oriented Programming (ROP) [25, 36] is a more causing execution to deviate from the control-flow graph. advanced form of code-reuse attack that lets the attacker This paper provides the following contributions: perform arbitrary computation solely by reusing existing code. It relies upon short instruction sequences (called 1. formalization and evaluation of a space of different “gadgets”) that end with an indirect branch instruction. kinds of CFI schemes; This allows them to be chained, so the attacker can 2. new attacks on fully-precise static CFI, which reveal perform arbitrary computation by executing a carefully- fundamental limits on the effectiveness of CFI; chosen sequence of gadgets. ROP can be generalized 3. evidence that existing metrics for CFI security are to use indirect jump or call instructions instead of re- ineffective; turns [4, 7]. 4. evidence that CFI without a shadow stack is broken; 5. widely applicable Turing-complete attacks on CFI with shadow stacks; and, 2.4 Non-Control-Data Attacks 6. practical case studies of the security of fully-precise A non-control-data attack [8] is an attack where a mem- static CFI for several existing applications. ory corruption vulnerability is used to corrupt only data, 2 162 24th USENIX Security Symposium USENIX Association but not any code pointer. (A code pointer is a pointer 3 Threat model and attacker goals which refers to the code segment, for example, a re- turn address or function pointer.) Depending on the Threat model.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages17 Page
-
File Size-