Points: 300 Solves: 14 Category: Exploitation Description: You can use “./bash”, if necessary.
Unfortunately we didn’t solve this challenge during the competition but only afterwards with the help of Ricky from PPP on how to bypass the seccomp sandbox. However, the solution blew my mind so bad, that I just had to document and share the exploitation method. Enjoy…
It’s a 64bit binary and before Main in the init constructor we have the following functions executed:
init_heap mmaps a new page with
rwx permissions that’s going to be used as a heap structure.
init_seccomp runs seccomp with filter to blacklist the following syscalls
If we run the application, we can see that it’s just as the name says, a diary. It allows you to input a date and a note.
And if look at the disassembly, we can see there’s not much going on. A non vulnerable
getInt function to take our menu choice and if statements for each of the functions
In this function we see a call to a non vulnerable function
Input_date that asks us for a date in the specified format and properly checks for the date range. After it returns it allocates a chunk on the heap (whenever I say the heap, I mean the fake heap created by the mmaped page with rwx permissions) of size 0x20 and copies the date struct there. Next it asks us for a positive int size for the note which passes to malloc. Next, this malloc chunk for the note and the
int size+1 are passed to the
getnline function for input. The
getnline function is going to read
int size+1, and if you are familiar with the heap’s structure this additional byte can overwrite the next chunk’s metadata, and this is exactly what we are going to exploit.
This function walks the sorted date list, grabs the date entry we would like to print and prints its’ content. We are going to use this function to leak the address of the heap without actually using any memory corruption vulnerabilities.
Delete_entry first finds the date entry structure we would like to delete, unlinks it from the list and frees the associated chunks. The big thing here is that all the heap manipulating functions
malloc/free/unlink_freelist are home-made by the organizers and part of the main module, they are not libc functions ! That means we can literally apply any heap exploitation method known to mankind.
First we need to leak the address of the heap. How to do that? By allocating two small chunks, freeing them and allocating a bigger chunk of size the sum of the two small chunks. This will cause the two smaller chunks to be linked in the free-list. This just means that the bigger chunk’s data section will contain pointers to the heap. Next we allocate just enough data to reach the
chunk1->next*, and since the data for the note is not null terminated when we print the bigger show with
show_entry it will leak that pointer.
To create a write anywhere condition, we are going to exploit the
unlink_freelist function. This function runs when it needs to coalesce two neighboring free chunks.
And how to create two adjacent free chunks while controlling their
prev pointers ? Well, using the
int size+1 vulnerability in
getnline. We can malloc two chunks of exactly 32 bytes and overwrite the next chunk’s metadata with a byte which LSB is 0. Now we have a chunk with data field under our control but marked as free in the next chunk’s metadata.
Simply put, we need to create two free chunks and place the
address(-8) we want to write to in
chunk[8:16] and the data we want to write in
chunk[:8], then free that chunk.
Here comes the crazy part ! So we have write anywhere anything and we have the address of the heap which is
rwx. We can just place shellcode there and replace exit@GOT with the address of the shellcode. Yea, if only we could execute execve… remember, seccomp ?
Apparently we can switch the mode from 64bit to 32bit and execute 32bit shellcode with execve being a different syscall seccomp can’t stop us anymore ! And switching the mode seems to be very easy, all we have to do is use the
retf (return far) instruction which is going to pop 2 values off the stack. The first being the regular value for EIP and the second for the
CS register, 0x23 for 32bit mode and 0x33 for 64bit mode.
- Thanks again Ricky Zhou