The wide-spread adoption of system defenses such as the randomization of code, stack, and heap raises the bar for code-reuse attacks. Thus, attackers utilize a scripting engine in target programs like a web browser to prepare the code-reuse chain, e.g., relocate gadget addresses or perform a just-in-time gadget search. However, many types of programs do not provide such an execution context that an attacker can use. Recent advances in data-oriented programming (DOP) explored an orthogonal way to abuse memory corruption vulnerabilities and demonstrated that an attacker can achieve Turing-complete computations without modifying code pointers in applications. As of now, constructing DOP exploits requires a lot of manual work. In this paper, we present novel techniques to automate the process of generating DOP exploits. We implemented a compiler called Steroids that compiles our high-level language SLANG into low-level DOP data structures driving malicious computations at run time. This enables an attacker to specify her intent in an application- and vulnerability-independent manner to maximize reusability. We demonstrate the effectiveness of our techniques and prototype implementation by specifying four programs of varying complexity in SLANG that calculate the Levenshtein distance, traverse a pointer chain to steal a private key, relocate a ROP chain, and perform a JIT-ROP attack. Steroids compiles each of those programs to low-level DOP data structures targeted at five different applications including GStreamer, Wireshark, and ProFTPd, which have vastly different vulnerabilities and DOP instances. Ultimately, this shows that our compiler is versatile, can be used for both 32- and 64-bit applications, works across bug classes, and enables highly expressive attacks without conventional code-injection or code-reuse techniques in applications lacking a scripting engine.
Just-in-time return-oriented programming (JIT-ROP) is a powerful memory corruption attack that bypasses various forms of code randomization. Execute-only memory (XOM) can potentially prevent these attacks, but requires source code. In contrast, destructive code reads (DCR) provide a trade-off between security and legacy compatibility. The common belief is that DCR provides strong protection if combined with a high-entropy code randomization. The contribution of this paper is twofold: first, we demonstrate that DCR can be bypassed regardless of the underlying code randomization scheme. To this end, we show novel, generic attacks that infer the code layout for highly randomized program code. Second, we present the design and implementation of BGDX (Byte-Granular DCR and XOM), a novel mitigation technique that protects legacy binaries against code inference attacks. BGDX enforces memory permissions on a byte-granular level allowing us to combine DCR and XOM for legacy, off-the-shelf binaries. Our evaluation shows that BGDX is not only effective, but highly efficient, imposing only a geometric mean performance overhead of 3.95% on SPEC.
With the general availability of closed-source software for various CPU architectures, there is a need to identify security-critical vulnerabilities at the binary level to perform a vulnerability assessment. Unfortunately, existing bug finding methods fall short in that they i) require source code, ii) only work on a single architecture (typically x86), or iii) rely on dynamic analysis, which is inherently difficult for embedded devices. In this paper, we propose a system to derive bug signatures for known bugs. We then use these signatures to find bugs in binaries that have been deployed on different CPU architectures (e.g., x86 vs. MIPS). The variety of CPU architectures imposes many challenges, such as the incomparability of instruction set architectures between the CPU models. We solve this by first translating the binary code to an intermediate representation, resulting in assignment formulas with input and output variables. We then sample concrete inputs to observe the I/O behavior of basic blocks, which grasps their semantics. Finally, we use the I/O behavior to find code parts that behave similarly to the bug signature, effectively revealing code parts that contain the bug. We have designed and implemented a tool for cross architecture bug search in executables. Our prototype currently supports three instruction set architectures (x86, ARM, and MIPS) and can find vulnerabilities in buggy binary code for any of these architectures. We show that we can find Heart bleed vulnerabilities, regardless of the underlying software instruction set. Similarly, we apply our method to find backdoors in closed source firmware images of MIPS- and ARM-based routers.
The art of finding software vulnerabilities has been covered extensively in the literature and there is a huge body of work on this topic. In contrast, the intentional insertion of exploitable, security-critical bugs has received little (public) attention yet. Wanting more bugs seems to be counterproductive at first sight, but the comprehensive evaluation of bug-finding techniques suffers from a lack of ground truth and the scarcity of bugs. In this paper, we propose EvilCoder, a system to automatically find potentially vulnerable source code locations and modify the source code to be actually vulnerable. More specifically, we leverage automated program analysis techniques to find sensitive sinks which match typical bug patterns (e.g., a sensitive API function with a preceding sanity check), and try to find data-flow connections to user-controlled sources. We then transform the source code such that exploitation becomes possible, for example by removing or modifying input sanitization or other types of security checks. Our tool is designed to randomly pick vulnerable locations and possible modifications, such that it can generate numerous different vulnerabilities on the same software corpus. We evaluated our tool on several open-source projects such as for example libpng and vsftpd, where we found between 22 and 158 unique connected source-sink pairs per project. This translates to hundreds of potentially vulnerable data-flow paths and hundreds of bugs we can insert. We hope to support future bug-finding techniques by supplying freshly generated, bug-ridden test corpora so that such techniques can (finally) be evaluated and compared in a comprehensive and statistically meaningful way.
The art of finding software vulnerabilities has been covered extensively in the literature and there is a huge body of work on this topic. In contrast, the intentional insertion of exploitable, security-critical bugs has received little (public) attention yet. Wanting more bugs seems to be counterproductive at first sight, but the comprehensive evaluation of bug-finding techniques suffers from a lack of ground truth and the scarcity of bugs.
Conceptually, this may involve extracting a signature from a discovered bug and developing an algorithm to effectively analyse a set of binary executables from applications for the presence of the signature. The challenges include describing what a suitable signature might be and designing a robust algorithm that can withstand syntactical variations due to the compilation process. Ideally, it should also be proved that the bug is reachable, since non-reachable bugs need not be patched.
Code reuse attacks allow an adversary to impose malicious behavior on an otherwise benign program. To mitigate such attacks, a common approach is to disguise the address or content of code snippets by means of randomization or rewriting, leaving the adversary with no choice but guessing. However, disclosure attacks allow an adversary to scan a process-even remotely- and enable her to read executable memory on-the-fly, thereby allowing the just-in-time assembly of exploits on the target site.In this paper, we propose an approach that fundamentally thwarts the root cause of memory disclosure exploits by preventing the inadvertent reading of code while the code itself can still be executed. We introduce a new primitive we call Execute-no-Read (XnR) which ensures that code can still be executed by the processor, but at the same time code cannot be read as data. This ultimately forfeits the self-disassembly which is necessary for just-in-time code reuse attacks (JIT-ROP) to work. To the best of our knowledge, XnR is the first approach to prevent memory disclosure attacks of executable code and JIT-ROP attacks in general. Despite the lack of hardware support for XnR in contemporary Intel x86 and ARM processors, our software emulations for Linux and Windows have a run-time overhead of only 2.2% and 3.4%, respectively.
Recently, many defenses against the offensive technique of return-oriented programming (ROP) have been developed. Prominently among them are kBouncer, ROPecker, and ROPGuard which all target legacy binary software while requiring no or only minimal binary code rewriting. In this paper, we evaluate the effectiveness of these Anti-ROP defenses. Our basic insight is that all three only analyze a limited number of recent (and upcoming) branches in an application’s control flow on certain events. As a consequence, an adversary can perform dummy operations to bypass all employed heuristics. We show that it is possible to generically bypass kBouncer, ROPecker, and ROPGuard with little extra effort in practice. In the cases of kBouncer and ROPGuard on Windows, we show that all required code sequences can already be found in the executable module of a minimal 32-bit C/C++ application with an empty main() function. To demonstrate the viability of our attack approaches, we implemented several proof-of-concept exploits for recent vulnerabilities in popular applications; e.g., Internet Explorer 10 on Windows 8.
Software vulnerabilities still constitute a high security risk and there is an ongoing race to patch known bugs. However, especially in closed-source software, there is no straightforward way (in contrast to source code analysis) to find buggy code parts, even if the bug was publicly disclosed. To tackle this problem, we propose a method called Tree Edit Distance Based Equational Matching (TEDEM) to automatically identify binary code regions that are "similar" to code regions containing a reference bug. We aim to find bugs both in the same binary as the reference bug and in completely unrelated binaries (even compiled for different operating systems). Our method even works on proprietary software systems, which lack source code and symbols. The analysis task is split into two phases. In a preprocessing phase, we condense the semantics of a given binary executable by symbolic simplification to make our approach robust against syntactic changes across different binaries. Second, we use tree edit distances as a basic block-centric metric for code similarity. This allows us to find instances of the same bug in different binaries and even spotting its variants (a concept called vulnerability extrapolation ). To demonstrate the practical feasibility of the proposed method, we implemented a prototype of TEDEM that can find real-world security bugs across binaries and even across OS boundaries, such as in MS Word and the popular messengers Pidgin (Linux) and Adium (Mac OS).
Runtime attacks that exploit software vulnerabilities are still an important concern nowadays. Even smartphone operating systems such as Apple's iOS are affected by such attacks since the system is implemented in Objective-C, a programming language that enables attacks such as buffer overflows. As a generic protection technique against a whole class of attacks, control-flow integrity (CFI) offers some interesting properties. Recent work demonstrated that CFI can be implemented on iOS by patching the binary during the loading process and adding an instrumentation layer that enforces CFI during runtime. However, this approach is of little practical value since it requires a jailbroken device, which hinders wide employment. Furthermore, binary patching has a certain performance impact. In this paper, we show how CFI can be implemented directly within a compiler, making the approach widely deployable on all kinds of iOS devices. We extend the LLVM compiler and add our CFI enforcement approach during the compilation phase of a given app. An empirical evaluation shows that the size and performance overhead is reasonable.
Computer platform peripherals such as network and management controller can be used to attack the host computer via direct memory access (DMA). DMA-based attacks launched from peripherals are capable of compromising the host without exploiting vulnerabilities present in the operating system running on the host. Therefore they present a highly critical threat to system security and integrity. Unfortunately, to date no OS implements security mechanisms that can detect DMA-based attacks. Furthermore, attacks against memory management units have been demonstrated in the past and therefore cannot be considered trustworthy. We are the first to present a novel method for detecting and preventing DMA-based attacks. Our method is based on modeling the expected memory bus activity and comparing it with the actual activity. We implement BARM, a runtime monitor that permanently monitors bus activity to expose malicious memory access carried out by peripherals. Our evaluation reveals that BARM not only detects and prevents DMA-based attacks but also runs without significant overhead due to the use of commonly available CPU features of the x86 platform.