Write me a Book
Give back to the library! Share your thoughts and experiences!
The flag can be found in /flag
nc 220.127.116.11 12346
To manage to read the flag we have to:
- create overlapping chunks due to an oob write vulnerability in
- tcache poisoning thanks to the overlapping chunks
- Overwrite the first entry of
@booksto then be able to rewrite 4 entries of
@booksby setting a large size.
- With the read / write primitives of
environ, this way getting a libc and stack leak.
- This way we can simply ROP over a given stackframe.
Let’s take a look at the protections and the version of the libc:
So a very recent one with standards protections. Then let’s take a look at the binary:
$ checksec --file chall
The binary isn’t PIE based and does have a seccomp that allows only
exit. Which will make the exploitation harder (but not that much).
main looks like this:
int __cdecl main(int argc, const char **argv, const char **envp)
We have to give a signature (12 bytes max) sorted in
author_signatures, then the program is allocating a lot of chunks in
secure_library. Finally it calls
write_books which contains the main logic:
unsigned __int64 write_books()
There are basically three handlers:
1337, we can leak only one time the address of a given allocated chunk.
3free a chunk.
1add a book.
2edit a book.
Let’s take a quick look at each handler, first the free handler:
unsigned __int64 throw_book()
It only checks is the entry exists and if the index is in the right range. if it does it frees the entry and zeroes it.
Then, the add handler:
unsigned __int64 write_book()
We can allocate a chunk between
0x20 + 0x10 bytes and after we wrote in it the signature initially choose at the begin of the execution is put right after the end of the input.
Finally comes the handler where lies the vuln, the edit handler:
unsigned __int64 rewrite_book()
As you can read there is an out of bound write if we input
books[idx].size bytes, indeed given the chunk stores only
books[idx].size bytes the signature writes over the current chunk. And most of the time on the header (and especially the size) of the next chunk allocated in memory resulting an overlapping chunk.
Given we can get overlapping chunks we’re able to do tcache poisoning on the
0x40 tcachebin (to deeply understand why I advice you to read the exploit and to run it into gdb). At this point we can simply write the first entry of
@books that is stored at a fixed memory area within the binary (no PIE). In this new entry we could write a pointer to itself but with a large size in order to be able to write several entries of
@books. When it is done we could write these entries:
This way we can easily leak libc.
Leaking libc is very easy given we already setup the entries of
@books. We can replace
puts@plt. This way the next time free will be called on an entry, it will leak the datas towards which the entry points. Which means
free(book) leaks the address of stdout within the libc.
STDOUT = 0x21a780
Leaking the libc is cool but given the binary has a seccomp we cannot write one_gadgets on
__free_hook or within the GOT (of the libc or of the binary) because of the seccomp. We have to do a ROPchain, to do so we could use
setcontext but for this libc it is made around
rdx that we do not control. Or we could simply leak
environ to get the address of a stackframe from which we could return. That’s what we gonna do on the
Everything is ready for the ROPchain, we cannot use mprotect to use a shellcode within the seccomp forbids it. We just have to set the first entry to the stackframe we’d like to hiijack and that’s it, then we just need call edit on this entry and the ROPchain is written and triggered at the return of the function!
rop = pwn.ROP(libc, base=stackframe_rewrite)
nasm@off:~/Documents/pwn/greycat/writemeabook/dist$ python3 exploit.py REMOTE HOST=18.104.22.168 PORT=12346
That was a nice medium heap challenge, even though that was pretty classic. You can find the tasks and the exploit here.
Final exploit (with comments):