CS 105

Return-Oriented Programming

Performing code-injection attacks on the program rtarget is much more difficult than it is for ctarget, because it uses two techniques to thwart such attacks:

  • Randomization The stack positions differ from one run to another. This defense makes it impossible for you to determine where your injected code will be located in memory.
  • Nonexecutable Memory The memory holding the stack is marked as nonexecutable, so even if you could set the program counter to the start of your injected code, the program would fail with a segmentation fault.

Return-Oriented Programming

Fortunately (for doing this lab), clever people have devised strategies for getting useful things done in a program by executing existing code, rather than injecting new code. The most general form of this approach is referred to as return-oriented programming (ROP).

  • R. Roemer, E. Buchanan, H. Shacham, and S. Savage. “Return-oriented programming: Systems, languages, and applications”. ACM Transactions on Information System Security, 15(1):2:1–2:34, March 2012.

  • E.J. Schwartz, T. Avgerinos, and D. Brumley. “Q: Exploit hardening made easy”. In USENIX Security Symposium, 2011.

The ROP strategy is to identify byte sequences within an existing program that consist of one or more instructions followed by the ret instruction. Such a segment is referred to as a gadget.

The following figure illustrates how the stack can be set up to execute a sequence of \( n \) gadgets:

The stack contains a sequence of gadget addresses. Each gadget consists of a series of instruction bytes, with 0xc3 (the ret instruction) as the final byte of the gadget. When the program executes a ret instruction starting with this configuration, it will initiate a chain of gadget executions, with the ret instruction at the end of each gadget causing the program to jump to the beginning of the next.

A gadget can make use of code corresponding to assembly-language statements generated by the compiler, especially ones at the ends of functions. In practice, there may be some useful gadgets of this form, but usually not enough to implement many important operations. For example, it is highly unlikely that a compiled function would have popq reg as its last instruction before ret. But with a byte-oriented instruction set such as x86-64, a gadget can often be found by extracting patterns from other parts of the instruction byte sequence.

For example, one version of rtarget contains code generated for the following C function:

void setval_210(unsigned *p)
{
    *p = 3347663060U;
}

The chances of this function being useful for attacking a system seem pretty slim. But, the disassembled machine code for this function shows an interesting byte sequence:

0000000000400f15 <setval_210>:
  400f15:   c7 07 d4 48 89 c7       movl   $0xc78948d4,(%rdi)
  400f1b:   c3                      retq

Ignoring the first three bytes at address 0x400f15, we have the byte sequence 48 89 c7, which encodes the instruction movq rax, rdi.

See tables below for the encodings of several useful instructions (movq, movl, popq, and nop).

Our cherry-picked sequence is followed by byte value c3, which encodes the ret instruction. So the function starts at address 0x400f15, and the sequence starts on the fourth byte of the function. Thus this code contains a gadget that has a starting address of 0x400f18 that copies the 64-bit value in register rax to register rdi.

The Gadget Farm

Your code for rtarget contains a number of functions similar to the setval_210 function shown above. They all reside in a region we refer to as the gadget farm.

The C code for your (unique) gadget farm is included as farm.c in the tar file you downloaded.
Your job is to identify useful gadgets in the gadget farm and use them to perform attacks similar to those you did in Phases 2 and 3.

Important: The gadget farm is demarcated by functions start_farm and end_farm in your copy of rtarget.

Do not attempt to construct gadgets from other portions of the program code.

Steps

Rules for This Assignment

  • You must do the assignment on wilkes.

  • Your solutions may not use attacks to circumvent the validation code in the programs.

    Specifically, any address you incorporate into an attack string for use by a ret instruction should be to one of the following destinations:

    • The addresses for functions touch1, touch2, or touch3.
    • The address of your injected code.

    • The address of one of your gadgets from the gadget farm.

  • You may only construct gadgets from file rtarget with addresses ranging between those for functions start_farm and end_farm.

  • Your exploit string must not contain byte value 0x0a (ASCII newline or \n) because the Gets function uses 0x0a to detect the end of a string.

  • hex2raw expects two-digit hex values separated by one or more white spaces.

    So if you want to create a byte with a hex value of 0, you must write it as 00. To create the word 0XDEADBEEF you should pass ef be ad de to hex2raw (note the reversal required for little-endian byte ordering).

  • The hex2raw page also contains examples of using shell I/O redirection (< and >) and pipes (|) on the command line, as shown in examples.

Instruction Tables

All values are shown in hexadecimal.

Byte Encodings of movq (movq S, D) Instructions

Warning: could not open file Content/labs/attack/rop-attacks/tables/encodings-movq.md

Byte Encodings of popq Instructions

Warning: could not open file Content/labs/attack/rop-attacks/tables/encodings-popq.md

Byte Encodings of movl (movl S, D) Instructions

Warning: could not open file Content/labs/attack/rop-attacks/tables/encodings-movl.md

Byte Encodings of 2-Byte Functional Nop Instructions

Warning: could not open file Content/labs/attack/rop-attacks/tables/encodings-nop.md

To Complete This Part of the Assignment

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)