tl;dr
- linux heap exploitation challenge with glibc 2.30
Challenge points: 418
No. of solves: 19
Solved by: slashb4sh
A glibc heap Note challenge
1 | Remain |
Add
- malloc(0x48), fixed size
- read input into chunk
- check if space available in table[10]
- if full are there, then free chunk, else add to table
Edit
- Edit a chunk with size as strlen(content in the given table idx)
Delete
- Free a table[idx]
- table[idx] not nulled out, leading to
Use after Free
glibc 2.30 has double free check just like 2.29
The tcache structure’s address is used as cookie in a freed chunk in tcache. When a chuunk is freed ino the tcache.
1 | static __always_inline void |
With subsequent free, if the key value is equal to tcache structure’s address, then all the chunks in the tcache linked list of the particular size is checked in a loop for double free.
1 | tcache_entry *e = (tcache_entry *) chunk2mem (p); |
Since we have use after free in edit function, we can overwrite the key to bypass the check,… oops wait a minute, the edit function uses strlen to get the size of the edit which means bypass is not easy.
But we still can change the next pointer of a freed tcache chunk, giving an arbitary write in the heap
by partialy overwriting freed chunk’s next pointer.
Exploitation
Since there is no show function, we will have to overwrite the stdout file structure to leak libc addresses. This directed my ideas to getting a parial overwrite to a freed tcache chunk with a libc address as the next pointer.
The size is fixed to 0x48, filling the tcache with these chunk will only put them in fastbin. We have to change the size of the chunk and then free it to get libc address as fd.
Remember that pointers in the table are not nulled out, so we have to finish the exploit with 10 allocations.
After a lot of thinking, this is what I came up with,
- use the partial overwrite to get write to the tcache structure
- overwrite the count for the 0xa0 chunk to 0x7 in the tcache structure
- now, when we free a 0xa0 chunk it will be inserted into the unsorted bin
- To free a 0xa0 chunk we partially overwrite the fd of free chunk to point above the first chunk allocated so as to overwrite the size.
- Set the size as 0x51 itself and free it once
- Change the size to 0xa1 and free it, I chose to overwrite with 0xa0, as the next chunk size fields will be already set and chunk will be inserted into the unsorted bin without any hazzles.
- As we have a free tcache chunk pointing to a libc address, partially overwrite the libc address to point to stdout.
- Overwrite the
stdout->flags
with0xfbad1800
and partiallly overwrite thewrite_base
to\x00
to dump a region of memory with the next puts call. - Now overwrite the fd of a free tcache chunk to get overwrite
__free_hook
Following all these steps I had already consumed 9 allocations out of the possible 10.
But I need two more allocations to write system
to __free_hook
Looking at the add functions again, we can notice that an allocation is made, our input is read into it and then free is called if table is full. This satisfies our requiredments perfectly.
Use the 10th allocation, and then 11th one to overwrite __free_hook
. system
is called for us within add functionality and we get shell :)
**Note: ** There is a 4 bit bruteforce for tcache structure and another 4 bit bruteforce to get stdout. Luckily I got shell in remote server in the 4th or 5th try.
1 | from pwn import * |