Exploit Programming
Exploit Programming
In memory of Len Sassaman, who articulated many of the following observations, connecting the mundane and the deeply theoretical aspects of hacking .
Sergey Bratus is a Research Assistant Professor of Computer Science at dartmouth College. He sees state-of-the-art hacking as a distinct research and engineering discipline that, although not yet recognized as such, harbors deep insights into the nature of computing. He has a Phd in mathematics from Northeastern University and worked at BBN Technologies on natural language processing research before coming to dartmouth. [email protected] Michael E. Locasto is an assistant professor in the Computer Science department at the University of Calgary. He seeks to understand why it seems difficult to build secure, trustworthy systems and how we can get better at it. He graduated magna cum laude from The College of New Jersey (TCNJ) with a BSc degree in computer science. dr. Locasto also holds an MSc and Phd from Columbia University. [email protected] Meredith L. Patterson is a software engineer at Red Lambda. She developed the first language-theoretic defense against SQL injection in 2005, as a Phd student at the University of Iowa, and has continued expanding the technique ever since. She lives in Brussels, Belgium. [email protected]
Len Sassaman was a Phd student in the COSIC research group at katholieke Universiteit Leuven. His early work with the Cypherpunks on the Mixmaster anonymous remailer system and the Tor Project helped establish the field of anonymity research, and in 2009 he and Meredith Patterson began formalizing the foundations of languagetheoretic security, which he was working on at the time of his death in July 2011. He was 31.
Anna Shubina chose Privacy as the topic of her doctoral thesis and was the operator of dartmouths Tor exit node when the Tor network had about 30 nodes total. She is currently a research associate at the dartmouth Institute for Security, Technology, and Society and manages the CRAWdAd.org repository of traces and data for all kinds of wireless and sensor network research. [email protected]
Hacker-driven exploitation research has developed into a discipline of its own, concerned with practical exploration of how unexpected computational properties arise in actual multi-layered, multi-component computing systems, and of what these systems could and could not compute as a result . The staple of this research is describing unexpected (and unexpectedly powerful) computational models inside targeted systems, which turn a part of the target into a so-called weird machine programmable by the attacker via crafted inputs (a .k .a . exploits) . Exploits came to be understood and written as programs for these weird machines and served as constructive proofs that a computation considered impossible could actually be performed by the targeted environment . This research defined and fulfilled the need of such practical exploration in real systems that we must trust . Hacker research has also dominated this area, while academic analysis of the relevant computational phenomena lagged behind . We show that at its current sophistication and complexity, exploitation research as a discipline has come full circle to the fundamental questions of computability and language theory . Moreover, application of language-theoretic and computationtheoretic methods in it has already borne impressive results, helping to discover and redefine computational models and weaknesses previously overlooked . We believe it is time to bring the hacker craft of finding and programming weird machines inside targets and the theorists understanding of computational models together for the next step in designing secure, trustworthy computing systems .
;login: dEC E M B E R 2 0 1 1
13
For readers who concentrated on the details of constructing the shellcode (and encountered a hands-on exposition of syscalls and ABI for the first time), it was easy to miss the fact that both the implicit data flow and the subsequent transfer of control were performed by the programs own code, borrowed by the exploit for its own purposes . Yet it was this borrowed code, the copying loop of strcpy() and the functions post-amble, that added up to the remote execution call as good as any API, into which the shellcode was fed . This borrowing turned out to be crucial, far more important than the details of shellcodes binary instructions, as Solar Designer showed next year (1997): more of the targets code could be borrowed . In fact, enough code could be borrowed that there was no longer any need to bring any of your own executable code to drop a shellthe target processs runtime already conveniently included such code, in libc . One just needed to arrange the overwriting stack data the way that borrowed code expected it, faking a stack frame and giving control to the snippet inside libcs exec() . This was a handy technique for bypassing non-executable stack protections, and it was pigeonholed by many as such . But its real meaning was much deeper: the entire processs runtime address space contents were ripe for borrowing, as long as one spoke the language of implicit data flows (owing to the targets input handling of logic flaws or features) that those borrowed pieces understood . The borrowings did not need to be a one-off: they could be chained . Quoting all of non-code contents of Tim Newshams 2000 post that probably holds the record for fewest words per idea value:
Heres an overflow exploit [for the lpset bug in sol7 x86] that works on a non-exec stack on x86 boxes . It demonstrates how it is possible to thread together several libc calls . I have not seen any other exploits for x86 that have done this . [10]
It was soon generalized to any code snippets present in the target, unconstrained by the codes originally intended function or granularity . Borrowed pieces of code could be strung together, the hijacked control flow linking them powered by their own effects with the right crafted data arranged for each piece . Gerardo (gera) Richarte, presenting this technique, wrote less than half a year later: Here I present a way to code any program, or almost any program, in a way such that it can be
14
;login:
vOL. 3 6, NO. 6
fetched into a buffer overflow in a platform where the stack (and any other place in memory, but libc) is executable [12] . So exploitation started to look like programmingwith crafted input data for overflows or other memory corruptionsin really weird assembly-like instructions (weird instructions) borrowed from the target . Nergals Advanced returninto-lib(c) Exploits [9] described the chaining of faked overflow-delivered stack frames in detail, each borrowed post-amble with its RET instruction bringing the control flow back to the next faked frame, and out into the targets code or libraries, in careful stitches . Also, the granularity of features so stitched can be mixed-andmatched: should the load addresses of the desired snippets be obscured (e .g ., with the help of PaX hardening), then why not craft the call to the dynamic linker itself to resolve and even load the symbols, as is its job, let it do its thing, and then go back to snippet-stitching? It does feel weird to so program with crafted data, but then actual assembled binary code is nothing but data to the CPUs in its fetch-decode-execute cycle, snippets of silicon circuits responsible for performing predictable actions when fed certain formatted inputs, then fetching more inputs . The exploit merely makes a processor out of the borrowed target code snippets, which implement the weird instructions just as digital logic implements conventional ones . Altogether, they make up a weird machine inside the target on which the craftedinput program executes . Weird instructions can be subtle, multi-step, and spread through the targets execution timeline . The original combination of strcpy() and a RET was a fair example, but just about any interface or library data interpretation code may offer a graceful specimen . For example, Doug Leas original memory allocator implementation keeps the freed blocks in a doubly linked list, realized as pointers in chunk headers interspersed with the chunks themselves . A bug in code writing to a heap-allocated buffer may result in a write past the end of the buffers malloc-ed chunk, overwriting the next chunks header with our crafted data . When the overwritten chunk is free-ed, the allocators bookkeeping code will then traverse and patch the doubly linked list whose pointers we now control . This gives us a weird MOV instruction that takes four overwritten chunk header bytes and writes them where another four bytes are pointing! This is beautiful, and we can program with it, if only we can cause the overwrite of a freed block and then cause the free() to happen . Such weird instruction techniques derived from a combination of an application-specific dynamically allocated buffer overwrite that corrupts the chunk headers and the normal malloc-ed chunk maintenance code are explained in detail in Vudo malloc tricks and Once upon a free() [7, 1] . Another famous example of a weird instruction is provided by the (in)famous printf-family format string vulnerabilities (in which the attacker could control the format string fed to aprintf()) . From the computational point of view, any implementation of printf() must contain a parser for the format string, combined with an automaton that retrieves the argument variables values from the stack and converts them to the appropriate string representations as specified by the %-expression . It was not commonly understood, however, that the %n specifier in the format string caused that automaton to write the length of the output string printed so
;login: dEC E MB E R 20 11
Exploit Programming
15
far to the stack-fetched addressand therefore the attacker who controlled the format string and the quantity of output could write that length-of-output to some completely unanticipated address! (Even though printf was not passed a proper pointer to such a variable, it would grab whatever was on the stack at the offset that argument would be at, and use that as a pointer .) What unites the printfs handling of the format string argument and an implementation of malloc? The weird instruction primitives they supply to exploits . This strange confluence is explained in Advanced Doug Leas malloc Exploits [5], which follows the evolution of the format string-based 4-bytes-write-anythinganywhere primitive in Advances in Format String Exploitation [14] to the malloc-based almost arbitrary 4 bytes mirrored overwrite, for which the authors adopted a special weird assembly mnemonic, aa4bmo . Such primitives enable the writing of complex programs, as explained by Gerardo Richartes About Exploits Writing [13]; Haroon Meers The(Nearly) Complete History of Memory Corruption [8] gives a (nearly) complete timeline of memory corruption bugs used in exploitation . Remarkably, weird machines can be elicited from quite complex algorithms such as the heap allocator, as Sotirov showed with his heap feng shui techniques [16] . The algorithm can be manipulated to place a chunk with a potential memory corruption next to another chunk with the object where corruption is desired . The resulting implicit data flow from the bug to the targeted object would seem ephemeral or improbable to the programmer, but can in fact be arranged by a careful sequence of allocation-causing inputs, which help instantiate the latent weird machine . The recent presentation by Thomas Dullien (aka Halvar Flake) [3], subtitled Programming the Weird Machine, Revisited, links the craft of exploitation at its best with the theoretical models of computation . He confirms the essence of exploit development as setting up, instantiating, and programming the weird machine . The language-theoretic approach we discuss later provides a deeper understanding of where to look for weird instructions and weird machinesbut first well concentrate on what they are and what they tell about the nature of the target .
16
;login:
vOL. 3 6, NO. 6
advice to not open or click emails from untrusted sources was a lesser evil, all the sarcastic quotes in this paragraph notwithstanding . So long as our ideas met the computational reality we were dead right, and then those of us who missed the shift were embarrassingly wrong . Successful exploitation is always evidence of someones incorrect assumptions about the computational nature of the systemin hindsight, which is 20-20 . The challenge of practical security research is to reliably predict, expose, and demonstrate such fallacies for common, everyday computing systemsthat is, to develop a methodology for answering or at least exploring the above fundamental questions for these systems . This is what the so-called attack papers do .
;login: dEC E MB E R 20 11
Exploit Programming
17
approach to validation of softwarewhich, ironically, the hacker research community approaches rather closely in its modus operandi, as we will explain . In other words, a hacker research article first describes a collection of the targets artifacts (including features, errors, and bugs) that make the target programmable for the attacker . These features serve as an equivalent of elementary instructions, such as assembly instructions, and together make up a weird machine somehow embedded in the target environment . The article then demonstrates the attack as a program for that machineand we use the word machine here in the sense of a computational model, as in Turing machine, and similar to automaton in finite automaton . Accordingly, the most appreciated part of the article is usually the demonstration of how the targets features and bugs can be combined into usable and convenient programming primitives, as discussed above . The attack itself comes almost as a natural afterthought to this mechanism description .
18
;login:
vOL. 3 6, NO. 6
object: a secure server that relies on buggy libraries for its input processing is hardly trustworthy .
;login: dEC E MB E R 20 11
Exploit Programming
19
This suggests that studying the targets computational behavior on all possible inputs as a language-theoretic phenomenon is the way forward for designing trustworthy systems: those that compute exactly what we believe, and do not compute what we believe they cannot . Starting at the root of the problem, exploits are programs for the actual machinewith all its weird machinespresented as input (which is what crafted stands for) . This approach was taken by Sassaman and Patterson in their recent research [15, 6] . They demonstrate that computational artifacts (which, in the above terms, make weird machines) can be found by considering the targets input-processing routines as recognizers for the language of all of its valid or expected inputs . To date, language-theoretic hierarchies of computational power, and the targets language-theoretic properties, were largely viewed as orthogonal to security, their natural application assumed to be in compilation and programming language design . Sassaman and Pattersons work radically changes this, and demonstrates that theoretical results are a lot more relevant to security than previously thought . Among the many problems where theory of computation and formal languages meets security, one of paramount importance to practical protocol design is algorithmically checking the computational equivalence of parsers for different classes of languages that components of distributed systems use to communicate . Without such equivalence, answering the above questions for distributed or, indeed, any composed systems becomes mired in undecidability right from the start . The key observation is that the problem is decidable up to a level of computational power required to parse the language, and becomes undecidable thereafterthat is, unlikely to yield to any amount of programmer effort . This provides a mathematical explanation of why we need to rethink the famous Postels Principlewhich coincides with Dan Geers reflections on the historical trend of security issues in Internet protocols [4] .
References
[1] Once upon a free(), Phrack 57:9: http://phrack .org/issues .html?issue=57&id=9 . [2] Richard A . DeMillo, Richard J . Lipton, and Alan J . Perlis, Social Processes and Proofs of Theorems and Programs, technical report, Georgia Institute of Technology, Yale University, 1982: http://www .cs .yale .edu/publications/techreports/ tr82 .pdf . [3] Thomas Dullien, Exploitation and State Machines: Programming the Weird Machine, Revisited, Infiltrate Conference presentation, April 2011: http://www .immunityinc .com/infiltrate/2011/presentations/Fundamentals_of_exploitation _revisited .pdf . [4] Dan Geer, Vulnerable Compliance, ;login: The USENIX Magazine, vol . 35, no . 6, December 2010: http://db .usenix .org/publications/login/2010-12/pdfs/geer .pdf . [5] jp, Advanced Doug Leas malloc Exploits, Phrack 61:6: http://phrack .org/ issues .html?issue=61&id=6 . [6] Dan Kaminsky, Len Sassaman, and Meredith Patterson, PKI Layer Cake: New Collision Attacks against the Global X .509 Infrastructure, Black Hat USA, August 2009: http://www .cosic .esat .kuleuven .be/publications/article-1432 .pdf .
20
;login:
vOL. 3 6, NO. 6
[7]Michel MaXX Kaempf, Vudo malloc Tricks, Phrack 57:8: http://phrack .org/ issues .html?issue=57&id=8 . [8] Haroon Meer, The (Almost) Complete History of Memory Corruption Attacks, Black Hat USA, August 2010 . [9] Nergal, Advanced return-into-lib(c) Exploits: PaX Case Study, Phrack 58:4: http://phrack .org/issues .html?issue=58&id=4 . [10] Tim Newsham, Non-exec Stack, Bugtraq, May 2000: http://seclists .org/ bugtraq/2000/May/90 (pointed out by Dino Dai Zovi) . [11] Aleph One, Smashing the Stack for Fun and Profit, Phrack 49:14 . http:// phrack .org/issues .html?issue=49&id=14 . [12] Gerardo Richarte, Re: Future of Buffer Overflows, Bugtraq, October 2000: http://seclists .org/bugtraq/2000/Nov/32 . [13] Gerardo Richarte, About Exploits Writing, Core Security Technologies presentation, 2002 . [14] riq and gera, Advances in Format String Exploitation, Phrack 59:7: http:// phrack .org/issues .html?issue=59&id=7 . [15] Len Sassaman and Meredith L . Patterson, Exploiting the Forest with Trees, Black Hat USA, August 2010 . [16] Alexander Sotirov, Heap Feng Shui in JavaScript, Black Hat Europe, April 2007: http://www .blackhat .com/presentations/bh-europe-07/Sotirov/ Presentation/bh-eu-07-sotirov-apr19 .pdf .
;login: dEC E MB E R 20 11
Exploit Programming
21