mmap_thresholdwith null and trim top chunk size.
- Null out last 2 bytes of stdin’s
_IO_buf_baseand brute force to get allocation on stdin.
- Overwrite one of the jump tables with win function to get shell.
Challenge Points: 453
We had a really great time this weekend with this year’s edition of Alles CTF. I spent most of my time working on the challenge nullptr and in this post , I’ll be discussing the intended solution for the challenge.
PS: We could not solve this during the CTF but the exploit idea is worth sharing.
To begin with , we’d been provided with a pretty simple c source code which has 2 functionalities.
- The view function prints the content of an address passed , hence we can be assured of all leaks ;).
- The nuke function nulls out the content of an address passed.
Looks pretty simple doesn’t it?
Getting necessary leaks
Getting all required leaks is nothing but a trivial task.
Initially, we can directly get stack leak by passing any
non-numeric value to scanf. Let’s script it a bit.
Idea of exploitation
After carefully analyzing scanf’s source code, sherl0ck came up with the idea of calling malloc again by
In the depths of scanf ,there resides a function called IO_doallocbuf.
if (fp->_IO_buf_base == NULL)
The code is actually of the caller function of
_IO_doallocbuf which is
It calls malloc with a fixed size of
blk_sizet which is by default 0x1000 bytes.
From this point on , we were stuck , we tried nulling out the last 2 bytes of buf base in the hope of getting allocation at tcache structure , from there on we faked a 0x400 size arbitrary chunk in tcache and found another way to call malloc with size of 0x400 from stdout structure.
Well , getting allocation with stdout doesn’t actually give us arbitrary write.
The intended solution
Well , the intended solution is actually leveraging an mmap call from malloc. Let’s see how this can be done.
- Nulling out
mmap_thresholdwith triggers a different code path in malloc.
- Also , trimming top size by writing null misaligned finally calls mmap when malloc is invoked.
Now , all that we have to do is , brute force until an mmap happens near our stdin file structure and from there on , its a game over.
Let’s take our script forward.
buf_base = libc + 0x1ea9b8
Once there’s a hit , all that’s left is to partially overwrite
IO_buf_base and get allocation on stdin. Here , after getting allocation on stdin , we intend to overwrite malloc hook to get shell.
#Now we partially overwrite io buf base of stdin
An alternative approach
We could be all lazy and let brute force do the work. A simpler yet time consuming approach would be to overwrite the last 3 bytes of stdin’s
IO_buf_base and wait for the magic to happen. Eventually , in one of the runs , it would match with binary bss and you get a direct write to GOT table.
The challenge had really intersting concepts involved and we learnt quite alot. Kudos to the author Mrmaxmeier for the awesome challenge.
Here’s the original script of the author - Link