The idea is to identify security-critical software bugs so they can be fixed first.

ion in memory where functions push space for local variables, arguments to future calls, and other data onto the stack immediately after being called. A function return pops the allocated space off the stack. Thus, the stack grows a bit for each call and shrinks a bit on each return. the twist is we replace typical safety properties with an “exploitability” property, and the “verification” process becomes one of finding a program path where the exploitability property holds. contributed articles 78 CoMMuniCations of the aCM | feBRuARy 2014 | voL. 57 | No. 2 being overwritten in a variable update. Control-flow hijacks are an instance of a channeling vulnerability that arise when the control and data planes are not rigorously separated. For this particular example, an outof-bound write can clobber the return address. When sprintf executes, it copies data sequentially from name up the stack, starting from the address for sun _ path, as shown. The copy stops only when a zero integer, or ASCII NULL, is found, which is not necessarily when sun _ path runs out of space. A long name will clobber the saved local variables and eventually the saved return address. Since an attacker controls the values in name, and those values overwrite the return address, the attacker ultimately controls which instructions are executed when ud _ connect returns. Attackers must analyze the program to figure out exactly how many bytes to write, what constraints may be on the bytes, and what would be a good value with which to overwrite the return address. For acpi _ listen, a string of length 140 will overwrite the return address. The first 108B will be copied into space allocated for sun _ path. The next 28B on the stack are intended to hold local variables and saved register values. The final 4B overwrite the saved return address. When ud _ connect returns, the overwritten return address is popped off the stack into the IP register. The machine continues executing the instruction starting at the overwritten address. While this example overwrites the return address, a variety of other control data structures can be used to seize control; examples include function pointers, heap metadata, and C++ virtual function tables. Control is typically hijacked to run an attacker-supplied computation. The most basic attack is to inject executable code into the vulnerable process. More advanced techniques (such as command injection, return-to-libc, and return-oriented programming) are also possible (and in some cases can be automated as well31), but we omit such discussion here. A natural choice for the computation is to execute the command-line shell /bin/sh so the attacker is able to subsequently run any command When f calls g, f first puts g’s arguments onto the stack, then invokes g, typically through a call assembly instruction. The semantics of call includes pushing f’s return address onto the stack; that is, the address in f where execution (normally) continues once g terminates. Upon entrance, g creates space for its variables and other run-time information (such as saved register values). After g completes, g returns control to f by shrinking the created stack space for g and popping off the saved address into the IP register, typically through a ret instruction. A critical detail is that the popped value, regardless of whether it was the original value pushed by f or not, is used as the address of the next instruction to execute. If an attacker can overwrite that address, the attacker can gain control of execution. The stack frame just before sprintf is called on line 22 in the Figure. The flow of execution for creating the depicted stack includes six steps: Return address pushed onto the stack. When main called ud _ connect, main pushed the address of the next instruction to be executed (corresponding to line 13) onto the stack; Control transfer. main transferred control to ud _ connect; Local variable space allocated. ud _ connect allocated space for its local variables. On our computer, 108B were allocated for sun _ path and an additional 28B for other data (such as additional local variables and saved register values); Function body executed. The body of ud _ connect ran. When sprintf is called, a similar flow pushes a new return address on the stack and new space onto the stack for sprintf’s local variables; Local variable space deallocated. When ud _ connect returns, it first deallocates the local variable space, then pops off the saved return address into the IP register; and Return to caller. Under normal operation, the return address points to the instruction for line 13, and main resumes execution. The crux of a control-flow hijack is that memory is used to store both control data (such as return addresses) and program-variable values, but the control data is not protected from Governments worldwide are developing computer-warfare capabilities, and exploits have become a new type of ammunition. contributed articles feBRuARy 2014 | voL. 57 | No. 2 | CoMMuniCations of the aCM 79 Our research vision is to automate it. AEG uses verification techniques to transform the process of finding and deciding exploitability to reasoning in logic. At a high level, AEG consists of three steps: It first encodes what it means to exploit a program as a logical property; it then checks whether the exploitability property holds on a program path; and finally, for each path the property holds, it produces a satisfying input that exploits the program along the path. These steps are the cornerstones of AEG research. First, what exploitability properties do we encode, and how? In industry, an exploit could mean control-flow hijack, while an intelligence agency might also include information disclosures, and a safety board could include denial of service for critical services. Any single property may have many encodings, with some more efficient for automated tools to check than others. Second, what techniques and algorithms should a programmer employ to check a program? The general problem of checking programs for properties is called “software model checking,” encompassing a number of techniques (such as bounded model checking, symbolic execution, and abstract interpretation). Third, what does it take to implement real systems, and how do these systems perform on real software? The theory of AEG can be described with a small number of operations on a well-defined programming language that interacts with its environment in a few predicable, easy-tomodel ways. However, a real system must also contend with hundreds of CPU instructions and the tricky and complex ways programs interact with their environments. Sometimes even pedestrian yet necessary details are difficult to get right; for example, it took our team almost a year to stop finding bugs in our internal semantics for the x86 shift instructions (such as shl). The developers of Microsoft’s SAGE tool reported similar difficulties for the same instructions. Current AEG research primarily uses symbolic execution to check program paths for exploitability properties. At a high level, symbolic execution represents all possible inputs as with the privileges of the exploited process. In fact, executing a shell is so popular that colloquially any attacker code is called “shellcode. ” A classic approach is to give executable code as input to the program and redirect control flow to the given executable code. The executable code itself can be created by mimicking the assembly for execve("/bin/sh", args, NULL). Attackers introduce the shellcode to the vulnerable program as a normal string program input that is eventually decoded and executed as code. The final step of the attack is to overwrite the return address with the address of the shellcode. On our machine, sun _ path is at memory address 0xbffff274. The complete exploit for acpi _ listen (generated automatically by our AEG tools) is shown in the figure, where: Shellcode. The first bytes of the command line argument are the shellcode; the shellcode is 21B, and, in this case, the first 21B are copied into bytes 0–20 of sun _ path; Padding. The next 115B of input can be any non-zero, or non-NULL ASCII, value; the bytes are copied into bytes 21–107 of sun _ path and the additional space for other locals; and Shellcode address. The last 4B of input are the hex string 0x74 0xf2 0xff 0xbf. They overwrite the return address. When the return address is popped, the bytes become the address 0xbffff274 (because x86 is little endian), which is the address of the shellcode after it is copied to sun _ path. The figure shows the stack frame after supplying this string as a command-line argument following -s. When ud _ connect returns, the address 0xbffff274 is popped into the IP register, and the hardware fetches, decodes, and executes the bytes in sun _ path that, when interpreted as executable code, runs /bin/sh. When the shellcode runs, the attacker is able to run any command with the same privileges as the exploited program.