Baby Heap
pwn backdoorctf19
Just another babyheap challenge.
4a2a94e77876565371d12b4a28e09d7d
https://mega.nz/file/a2YHzagS#kgHUvfbbk7Xo2bW97nnIjQYdaMikc27CohnwVn8znJw
nc 51.158.118.84 17001
Flag format: CTF{…}
Created by: Nipun Gupta
Another heap challenge the binary had the following attributes:
1 | $ file babyheap |
Checking the security:
1 | $ checksec babyheap |
Partial RELRO which means we can actually write at global offset table this simplifies things a bit and also PIE is not enabled so we can access this addresses very easily without a leak.
The libc version is:1
2$ strings libc.so.6 | grep 'libc-'
libc-2.23.so
Exploit plan
So for those who want a very fast solution this my exploit plan:
- Use unsorted bin attack to overwrite the value global_max_fast by doing a 4 bit brute force.
- Create a fake chunk(0x31) where the saved sizes of malloc are saved (global variables).
- Use fastbin dup to malloc at the created fake chunk and overwrite a string pointer to atoi got.
- By using edit we can get an arbitrary write at atoi got, we want to change it to printf so we can leak libc.
- The program is not broken because printf returns the number of the printed bytes string so we still using the options to edit atoi got to system.
- Send ‘/bin/sh\x00’ to read and get a shell.
Binary analysis
The first thing we can see right at the beginning is mallopt(1,0);
From linux man pages:
1 | The mallopt() function adjusts parameters that control the behaviour of the memory-allocation functions (see malloc(3)). |
The parameter being modified is 1 from the symbols also from linux man pages:1
2
3
4
5
6
7/*Symbol param # default allowed param values
M_MXFAST 1 64 0-80 (0 disables fastbins)
M_TRIM_THRESHOLD -1 128*1024 any (-1U disables trimming)
M_TOP_PAD -2 0 any
M_MMAP_THRESHOLD -3 128*1024 any (or 0 if no MMAP support)
M_MMAP_MAX -4 65536 any (0 disables use of mmap)
*/
We know that 1 is M_MXFAST when 0 means fastbins become disabled…
Continuing our analysis we need to look for vulnerabilities, delete function has a double free vulnerability, there is a check at the beginning, but it’s only checking if this index was previously allocated, also another thing to note is that we are limited to 8 free’s, freeLimit_602088 is initialized to 8.
Another vulnerability can be found at edit, as in delete function there’s no check, so we have a UAF vulnerability here:
There’s another limitation to program there’s only 11 slots where the data is saved so we can only use 11 mallocs on our exploit.
Exploit
Modifying global_max_fast
There isn’t a print function so there’s no simple way to leak libc and also we can’t use fastbins because they were disabled, our first approach is to find a way re-enable fastbins.
This can be done if we find a way to modify global_max_fast into a big value, but how do we achieve this, we don’t even have libc to calculate the offset to global_max_fast ?
Well one thing we can is a 4 bit bruteforce, if we free a chunk into an unsortedbin:
That’s how we can find the address of global_max_fast, and why this variable in particular ? Because it controls the max size that malloc interprets a chunk as fastbin, and it’s current value is 10 because of mallopt.
We need to find a way to modify this value into a bigger number, we can do this by using an unsorted bin attack, we need to modify the bk to the address we want to modify minus 0x10.
This is how the exploit looks right now
1 | def exploit(): |
If we are successful we will modify global_max_fast:
Arbitrary write using fastbin dup
We can use fastbin dup now but still we don’t have any leaks, luckily we know that size of each data is being saved at 0x6020e0:
The data pointers to the strings are also saved in a global variable at ptr(0x602120):
This how it looks in memory in gdb:
I created a fake chunk at index 8 with malloc:
1 | add(8,0x31,'c'*0x10) # CREATE A FAKE CHUNK HERE |
Now we proceed to use fastbin dup to modify the fastbin linked list:
1 | # fastbin dup |
We edited the index 0 string pointer into atoi got, later with this we can modify atoi got into printf gaining a format string vulnerability to leak libc:
1 | s = '%7$s ' |
Finaly after getting system we change again atoi to system and send the /bin/sh string:
1 | r.sendlineafter("\n4) Exit\n>> ","AA") |
The shell is achieved after this:
1 | $ python babyheap.py REMOTE |
The full exploit:
1 | from pwn import * |