Don't like this style? Click here to change it! blue.css

Welcome .... Click here to logout

Daily Reminder: Mom's Spaghetti in glibc 2.32

2.32 ENCRYPTS the tcache bins with a heap address, so we have to leak a "key", be able to decrypt and encrypt.

Our compass through all of this is the desire for the following comfort food:

You're babies today and we're going to learn the warmth and love of the dining room table. So that as you venture into the wilderness you'll do your best to recreate this ritual in ever harsher environments.


The first update to MOM's Spaghetti is to move to glibc 2.32.

In the version we have good access to the glibc leak HAPPENS to have a null byte at the end...

So our leak never works.

So you have the job of getting a UAF to work from either the "smallbins" or the "largebins", but we've never talked about those.

The Bins

A story I want to tell you one day is the "fastbin dup". It is super clever, exists in ALL glibc versions and is relatively simple.

(Aside: TLDR on fastbin dup)

fastbin dup works like this:

            A = malloc(somefixedsize);
            B = malloc(somefixedsize);
            free(A);// BIN->A
            free(B);// BIN->B->A
            free(A);// BIN->A->B->A
            C = malloc(somefixedsize)//will be A
            fgets(C, 8, stdin)//send target to C now BIN->B->A->TARGET
            D = malloc(somefixedsize)//D will be B BIN->A->TARGET
            E = malloc(somefixedsize)//will be A again BIN->TARGET
            F = malloc(somefixedsize)//will be target! BIN empty

There are a couple gotchas, in order for that target to be successfully deployed it has to find a valid chunk size (i.e. 0x21) at the target.

OK I want to tell you that story, and to solve a bunch of problems like that.


As I went to write the notes and put together the right story I realized you will feel too much like a stranger in heapland.

There are a ton of little annoyances that will emerge in each new attack. In order for you to tackle them effectively you need a solid foundation.

So... I decided I'd first tell a different story. The story of the bins.

Your PCP for today is for you to tell me back this same story. You're an apprecntive in the old fashioned oral storytelling tradition.

My goal for today is that you can look at the basic malloc and basic free flow charts, grasp exactly what they mean and how they relate.

(There is also a moment where we should/could look at how the unsorted bins work although I'm not sure if we'll have time.)

Learning Objectives:

The FREE flowchart

The MALLOC flowchart

The Bins: what, why, how

The word bin is really a linked-list holding re-usable (free'd) chunks

OK there are 5 types of bins. The first 3 are the "old-school" bins that are the basic fundamental approach to the heap:

The other 2 types are the "new-school" bin types:

The Why of it all

So put yourself in the shoes of a developer making code that runs the world.

Every server, every database, every operating system in the world is going to run on your malloc implementation.

You hear, all day, every day, from people complaining about your performance or your security issues.

So... you profile like crazy. You try to understand, statistically, how people are really using you. What the ratio of mallocs/frees are, what the clustering patterns are, which sizes are requested most often, and in what order.

Every clock cycle matters.

Further, if you're servicing a server (you are) then each new socket or incoming connection will be a parallel thread of your socket process.

That means that the threads will actually SHARE the segments for your opcodes, glibc, and .data/.bss segments. Importantly your HEAP (and main_arena) ARE SHARED ACROSS THREADS. Not the stack or registers though.

OK the baseline story: smallbins

Small bins are doubly linked, one size per small bin in the range 0x20 to 0x3f0.

Let's pretend that the smallbins are populated with ready to malloc free'd chunks all lined up.

Then when it's time to malloc and we've decided to use a smallbin we find the linked-list / bin for that size and unlink the VICTIM CHUNK (the name for the one about to be malloc'd) follow its bk pointer and replace that with its fd_pointer, follow its fd_pointer and replace that with its bk pointer.

Then once it is unlinked we return the VICTIM address.

Here are a ton of pictures:

You'll note that there are 62 smallbins and they use 124 addresses in an arena. (A forward and backward pointer each.)

Another note: smallbins are FIFO not LIFO. frees are added to the head and mallocs are taken from the tail

Largebins: similar but different

Largebins are also doubly-linked, but now, for the sake of space in the arenas we have a range of sizes per bin.

Each bin has a unique range which does not intersect with any other smallbin or largebin

Because each bin has more than once size we have to do some sorting in order to speed things up.

The ranges in each bin get wider the larger the sizes are:

This section is the slowest to use and the other optimizations are essentially to not need to do this.

A normal free

When you free a chunk and fastbins/tcache are not involved then the process is roughly this:

Unsorted bins: the quick cache

Since frees tend to come in clusters (I am done with this entire ARRAY of stuff), it's best not to start doing weird sorting and merging things too quickly.

Once we go through the unsorted bin we will move what we find into either the smallbins or largebins

fastbins and tcache

OK I need to travel now, so here are some pictures for these last ones: