# DEF CON Quals 2018: It's a Me

Category: pwnable      |      Points: 124      |      Solves: 49      |      Challenge files

## Summary

This is a classic C++ menu challenge that features a UAF and heap overflow with a vtable pointer overwrite. The main heap techniques involve using a free unsorted bin chunk to leak a libc and heap address, as well as some feng shui to place an object in an overflow-able region on the heap. fortenforge, qzqxq, and I combined to reverse the binary and discover the 3 separate vulnerabilities.

## Reversing

When you first create a new Customer or login to this pizza kitchen, you have the option to order, cook, or admire Pizzas. When you order, you can specify Unicode emoji ingredients like 🍍 and 🍅. If you try to order a pizza with 🍍, you are kicked out and banned from ever logging in again.

When you ask to have your pizzas cooked, the ingredients are strcated together and checked with strstr — if a pizza contains only 🍅, it’s “good”, if it has 🍍, it’s “criminal” — then, a new Pizza object of the correct type is created. You can also provide an explanation string, which is malloced onto the heap and stored in the Customer. This explanation is then freed at the end of cook, if the number of good pizzas == total number of pizzas.

In pseudo-code, the Customer struct looks like

## Stage 1: Leak

You want to trick Mario into cooking a pineapple pizza first. We make a pizza with two ingredients, one ending in \xf0\x9f and another starting with \x8d\x8d that, when strcated together, give a Unicode pineapple (\xf0\x9f\x8d\x8d). Now you’ve made Mario upset! Your customer is then stored as a global variable upset_user. You also unlock a menu option to print the explanation field, which would be a UAF if the explanation were freed in cook. We can ensure that the explanation is freed by overflowing the 1-byte counter of total number of pizzas, with (16 bad + 1 good pizza) = 17 total pizzas % 16 = 1 total pizza.

What are the contents of a freed chunk that we can leak? If the chunk is >fastbin size (>0x80), when it is freed, it will be inserted into the unsorted bin, which is a doubly-linked list of recently freed chunks. The fd and bk pointers will thus be populated with the address of the unsorted bin, which is in the main_arena struct in libc. This gives us our libc leak.

We can also get a heap leak if the unsorted bin has another chunk when we free our explanation. In that case, when the explanation chunk is inserted, the fd pointer will be set to the other free chunk. The free explanation chunk then looks as follows:

This image from sploitfun is great for understanding the linked list structure of heap bins.

## Stage 2: Overflow

If we successfully cook a pineapple pizza, we are also given a new menu option to “explain ourselves” by overwriting our explanation. It reads 300 bytes into the explanation on the heap, even though our explanation was previously malloced with a smaller length (the length of our original explanation). IDA can’t detect/decompile jump tables for some reason, so here’s the assembly of the overflow:

This overflow allows us to overwrite whatever is after the explanation in the heap. With some grooming, we can try to get a Pizza object placed right after our explanation, so we can overwrite its contents — namely, the C++ vtable pointers for class functions.

A Pizza on the heap looks like this:

The goal, of course, is to overwrite the printPizza vtable ptr to a pointer to one_gadget, so that the next time we print the pizza in admire, we get a shell.

How do we ensure that the Pizza is placed right after our Customer’s explanation? If we malloc and free a large explanation, its free space will be used for other objects, and if we are lucky, a Pizza.

Lovely! Now, we perform our overflow, first writing one_gadget to the heap, then overflowing the Pizza with the heap ptr to one_gadget.

And when admire is called,

I learned the unsorted bin leak trick from Samurai’s Gulshan Singh in one of his writeups, who in turn learned it from PPP.