Rating: 5.0



# House of Sweets And Selfies

Welcome to the house of sweets and selfies. Come on in, there'll be heaps of fun!
(Well technically you can't come on in right now, but our Customer Service Team is available online 24/7 to relay all your service requests.) Server: nc 1337


I actually didn't have a working solution by the end of the competition. I only found that we could overwrite a tcache entry 2 hours prior to competition end.

The solution that I ended up finishing utilized a 64-byte heap overflow from when you modify a selfie. It will prepend a PNG header to your given input and overflow into the next region

This challenge required a bit of reading on jemalloc. There are a number of slides and talks on the topic from Blackhat/Infiltrate that I went through to solve this challenge. I also recommend using [shadow](https://github.com/CENSUS/shadow) with gdb when debugging.


To utilize the overflow to overwrite tcache, we need to allocate 10 selfies of size 0x1c00 to fill up the 0x1c00-sized runs so that when a new tcache 0x1c00 is allocated, it can be written to by modifying the 10th selfie. To force a new tcache entry to be created, we create our first cake of any size. This new tcache entry will be allocated at the first region within the last 0x1c00 run, which our overflow can write to. With shadow `jeruns` command, you can view this.

The tcache header we overflow looks seems to be defined as the `tcache_s` structure below:
typedef struct tcache_bin_s tcache_bin_t;

struct tcache_bin_s {
tcache_bin_stats_t tstats;
int low_water; /* Min # cached since last GC. */
unsigned lg_fill_div; /* Fill (ncached_max >> lg_fill_div). */
unsigned ncached; /* # of cached objects. */
* To make use of adjacent cacheline prefetch, the items in the avail
* stack goes to higher address for newer allocations. avail points
* just above the available space, which means that
* avail[-ncached, ... -1] are available items and the lowest item will
* be allocated first.
void **avail; /* Stack of available objects. */

struct tcache_s {
ql_elm(tcache_t) link; /* Used for aggregating stats. */
uint64_t prof_accumbytes;/* Cleared after arena_prof_accum(). */
ticker_t gc_ticker; /* Drives incremental GC. */
szind_t next_gc_bin; /* Next bin to GC. */
tcache_bin_t tbins[1]; /* Dynamically sized. */
* The pointer stacks associated with tbins follow as a contiguous
* array. During tcache initialization, the avail pointer in each
* element of tbins is initialized to point to the proper offset within
* this array.

Our 64-byte overflow allows us to overwrite every byte until the `tbins[0]->avail` pointer. The size of regions stored at `tbins[0]` are the smallest size, 0x8. So when a `malloc(8)` is ran, it will first query this tcache bin, before diving deeper into allocation. This is typically performed by checking if `ncached` is greater than 0 and if it is not, it will subtract `ncached` from `avail` and return the value stored there while decrementing `ncached` afterwards.

The reverse is also true, in that when a 0x8 size region is free'd it will be pushed onto the `tbins[0]->avail` stack. The push is performed by incrementing the `ncached` value and storing the free'd address at the address `avail - (ncached*sizeof(ptr))`.

Once we can overflow a tcache header, we can modify the `ncached` value so that it extends into a buffer that we control. We can also modify the `ncached` value to control what `malloc(0x8)` will return as well as control where a `free()` on a 0x8 size region is placed.

For our solution, utilized this control over `ncached` to obtain a heap leak, a libc leak, a stack leak, and then program control. All selfies mentioned below are modern and all cakes mentioned below are classic unless otherwise specified.

To obtain a heap leak, we allocate two cakes of size 0x8. We then modified `ncached` so that the next free'd address would overwrite the 1st cake's contents. So when we free'd the 2nd cake, it's address would be stored as the contents of the 1st cake. When you "baked" the cake, this gave us a heap leak.

To obtain a libc leak, we adjusted `ncached` so that `avail - (ncached * sizeof(ptr))` would point to the 1st cake. We then modifed the 1st cake's content to be the address of a heap location that contained a libc pointer minus 1 (`address - 1`). This is due to classic cakes having their first offset being set to NULL and we do not want our leak to be overwritten. We then have the next `malloc(0x8)` return the libc location minus minus 8 (`addr - 8`). For our next allocation, we allocate a hipster cake instead so that there is no NULL padded byte. This allows us to overwrite the NULL byte in the previous cake. After overwritting the NULL byte, when we `bake` the previous cake we recieve a libc leak.

To obtain a stack leak, we did the same method as for the libc leak, except our libc pointer was the `environ` pointer in libc. We allocated a classic cake at `environ_addr - 1` and a hipster cake at `environ_addr - 8`. Once we filled up the hipster cake with non-NULL bytes, we could `bake` the classic cake and obtain a stack leak.

To gain shell, we calculated the offset on the stack that the `do_sweets()` function would return to in `main()`. We overwrote that by allowing the next `malloc(0x8)` call to return a stack pointer to that return address. We then allocated a cake to get a pointer to this stack location and wrote the address of a one gadget (0x662C4) to get a shell.

Output of our solution running on the remote server:
Finished challenge
Heap leak: 0x79a622b0f8
Libc leak: 0x79a6818420
Libc base: 0x79a6787000
One gadget: 0x79a67ed2c4
Environ leak: 0x7ffb3135e8
[*] Switching to interactive mode

$ cat /data/local/tmp/flag

Original writeup (https://github.com/x64x6a/ctf-writeups/tree/master/SpamAndFlags_2020/house_of_sweets_and_selfies).