Don't like this style? Click here to change it! blue.css
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.
It's "easy" just:
This simple trick breaks in three ways:
OK the first issue is that your chunk will get "consolidated" with the top chunk.
The top chunk is the "wilderness" which is the boundary between allocated space and unallocated space.
There is always a number of bytes left in the top chunk stored at the boundary so the allocator can decide if there is room for the chunk you want.
Just always make sure you have a barrier chunk between you and the wilderness.
Think Jon Snow and the great wall keeping out the wildlings.
You'll see this top chunk business in the "free flowchart" in the "consolidate with top chunk" branch/box
In glibc 2.32 and beyond the singly linked lists in the heap use "safe-linking"
Safe-linking literally does this:
#define PROTECT_PTR(pos, ptr, type) \
((type)((((size_t)pos) >> PAGE_SHIFT) ^ ((size_t)ptr)))
#define REVEAL_PTR(pos, ptr, type) \
PROTECT_PTR(pos, ptr, type)
That is it XORs addesses with the heap address bit-shifted by 12.
Still again: it encrypts addresses with the RANDOM PART of the heap address, skipping those bottom 12 "000" bits
My pythonic pseudo-code hopefully makes this clear:
OK so how do we get around this?
This encryption isn't very strong, so if you've leaked it you can pretty quickly un-encrypt the leak:
BOOKMARK this script it's useful to keep around.
OK this isn't a solution so much as an excuse to teach you something very valuable.
It's not a solution because you don't get to pick the version of glibc used on the target server.
It IS USEFUL because the version on the server won't match your test environment so you MUST KNOW HOW TO EMULATE their environment.
The TLDR is this:
caveats:
libc.so.6
ld-linux-x86-64.so.2
There are other ways to do this but I find this one liner useful for students to know.
To fetch a copy of the library for any version of glibc use this tool: https://github.com/fr0ster/glibc-all-in-one
Most of the time a CTF problem will provide you the glibc, often they do not provide the linker.
We need to talk out the Tale of the 5 bins which are the 5 ways that glibc tries to recycle chunks.
The 5 bins are:
Safe-linking only applies to tcache and fastbins.
tcache is the first choice for recycling chunks.
If you can change things around a little bit you can get your free'd chunk to live in the unsorted bin.
Our first trick for "getting out of tcache" is to ask for something large than the biggest chunk tcache holds:
We finally get a leak. It's a leak into the heap...
That's nice I guess but it's not a glibc leak.
If you get a heap leak that is what it takes for you to ENCRYPT your own pointers in the future.
So hold on to this for the second phase of MOM'S SPAGHETTI
OK well the Solution C above actually gets a glibc leak. So that's cool.
Will leak an unencrypted glibc leak.
A doubly linked list will point back to the HEAD of the linked list.
That HEAD lives in glibc's main_arena
a data structure we're going to want to learn about.
Remember these?
The basic idea is that linked lists are just a sequence of pointers.
Here is a diagram of what linked singly-linked chunks look like:
Here is how adding a chunk to a "bin"/linked-list works:
Here is how popping a chunk from a "bin"/linked-list works:
Here is a "doubly linked" list which is the unsorted bin:
The job here is to know WHY each of the 5 bins exists.
Then to know HOW to get a chunk linked into any of the 5 bins.
This is the newest bin and probably should be the last one to understand because it's wackier than the others.
The why of it is that parallel computing will LOCK the glibc main_arena (all other bins) and if you're doing multi-threaded stuff you make it silly if they all wait for each other anyway.
It is a set of singly-linked lists where EVERY CHUNK in each tcache-bin has a FIXED SIZE.
The SIZES go from 0x20 to 0x410, so anything larger than that will NOT go into tcache when free'd, instead it goes into the UNSORTED BIN (which is doubly linked to glibc).
ALSO tcache LIMITS THE SIZE OF EACH BIN, so they keep track of HOW MANY chunks are in each BIN (linked-list) for each size.
The limit is 7, an 8th chunk of that size will no longer go into tcache (it might go into the fastbins).
The reason for the limit it to make sure DEFRAGMENTATION doesn't get too bad.
That diagram above is a sort of treasure map saying how to process data in the teal tcache segment we've been seeing every time we run vis
.
Make a free some chunks and watch the struct move.