Use After Free

In this assignment, you will:

  1. Locate a use-after-free vulnerability in a network server
  2. Find a sequence of inputs to trigger a virtual table pointer overwrite
  3. Exploit the overwrite to hijack control flow

Use After Free

Use-after-free vulnerabilities (UAF) arise when memory is used after it has been freed and reallocated to other program variables. UAFs have become extremely common in modern programs that perform many heap allocations and deallocations of different types over the lifetime of a program execution.

While UAFs can manifest in many ways, virtual table (vtable) pointer (vptr) overwrites are common. Consider the following example.

class A {
public:
    virtual void f() = 0;
};

class B : public A {
public:
    void f() override {}
};

class C : public A {
public:
    void f() override {}
};

void main() {
    A* x = new B();     // Allocate x
    delete x;           // Free x
    A* y = new C();     // Overwrite x's vptr
    x->f();             // Use attacker-controlled vtable
}

Here, the program first allocates a new instance of B and then deletes it. However, the pointer to that heap memory still exists. A subsequent heap allocation (y) may overlap the old allocation for x with attacker-controlled data. If a virtual function (f) is mistakenly invoked on the dangling pointer x, the corrupted vptr can be hijacked to point at a fake vtable. In turn, the fake vtable can hold an attacker-controlled pointer for f that, instead, kicks off a ROP chain.

In Canvas, you will find vuln06 which contains an exploitable UAF-based vptr overwrite vulnerability along with associated assets.

Fuzzing for Inputs

With careful analysis of a vulnerable program’s allocation pattern and the heap allocator’s behavior, it is often straightforward to engineer a sequence of program inputs that will deterministically lead to an exploitable vptr overwrite. However, as discussed in class, automating this search using a dynamic analysis such as programmatic debugging can make this search almost completely hands-off.

Combine a randomized test harness with checks for success conditions at the program points in vuln06 where vptr dereferences occur using the provided lldb-based script template. Derive a set of inputs that reliably lead to a controllable vptr overwrite.

Hijacking Control Flow

Once you have obtained control of a vptr, what remains is to redirect that vptr to a fake vtable you inject into memory. For this assignment, you do not have to deal with ASLR, and so debugger-discovered addresses can be used for this purpose. Once you have successfully controlled the instruction pointer, you can then construct a ROP chain.

As discussed in class, invoking system in libc with an attacker-controlled command string is suitable as a solution. However, in contrast to the stack cookie bypass example, you will first need to pivot the stack pointer into attacker-controlled memory to execute the rest of your ROP chain. You will also need to ensure 16-byte alignment of the stack pointer to avoid crashing the server due to ABI constraints. Finally, you might need to shift the stack pointer again before invoking system in order to maintain the integrity of the command string.

Construct a ROP chain to invoke an arbitrary server-side command.

Submission Instructions

  1. Upload a tgz archive to Canvas containing the following files:
    • A README.md describing what your attack does
    • The source code for your attack
    • A video demonstrating your attack while tracing the server in gdb. The video should clearly show the hijack of the virtual function call, the invocation of system, and the execution of your command.

© 2022 wkr