sunshine CTF 2018 - bookwriter
I just invented the printing press, but my competitor developed a machine called BookWriter to assist with writing books. His machine allows you to write pages in any order you want, remove pages you don’t want, and then publish the entire book. This new invention will bury my business!
I’d like you to do what you can to destroy his new machine. If you take over control of BookWriter and give me evidence, I’ll give you a reward!
nc chal1.sunshinectf.org 20002
Author: hackucf_kcolley
Attachment: bookwriter bookwriter.c libpwnableharness32.so libc xpl.py
That page number already looks intriguing, just doing a p/x
in gdb on it already shows something interesting, but where does this come from?
So, when the book gets initially created, current_page will point to g_cover
(which is an address on bss
). Thus, the page number shown in the first menu_input
can be used to leak an address to get around pie
.
Since book->current_page
will always point to the address of the current page, we can also use the page number for leaking heap
.
Just create a page, which will get malloc
ed on the heap, and the page number will show its address also.
Ok, easy leaks out of the way.
The next attack vector is an uaf
bug in removing pages:
For one, this looks pretty much like unsafe unlink
, so we might abuse this later on. But for now, we can observe, that the current page gets free
d, but book->current_page
will still point to the freed chunk.
A page is a chunk of size 0x10
, so we could now just create a new page with content of that size, which will overwrite the page metadata. With this we can control the text
pointer and also the prev
pointer.
We can use this to leak an arbitrary address.
- Create two pages
- Flip to previous page
- Remove the page
- Create another page with
text
pointing to the address we want to leak - Since this will create a new page, which is inserted after our currently freed page (whose metadata we just overwrite), flip to previous page again
- Read the content of the page (
text
)
Since, we’ll be leaking a lot to get this stuff also working on the remote machine, let’s generalize it
Armed with this, we can start leaking some more interesting addresses.
But to know, which values will be useful to us, let’s first think about, how this binary can be exploited at all.
From our leak, we know, that we can overwrite page metadata, by adding a new page after removing the current page.
Actually we can control the text
and prev
pointer for it.
Since, we’re controlling prev
, we can then write next
(pointing to the following page) to an arbitrary address.
_IO_file
would be a good target for this, but while this worked with my local libc, it stopped working when using the provided libc, so I trashed my exploit and went another way…
When you’ll publish
the book, it will print out the pages, and return to main.
In main
it will pop ecx
from the stack, and put esp to ecx-0x4
.
So, if we’d be able to overwrite the address, which get’s popped into ecx
we could control esp.
Right, we can store the stack address into prev (-0x4
). unlink
would then put the address of the next page there, pivoting the stack onto the heap right into our page. We’ll just have to prepare a ropchain waiting there, giving us a shell.
As it turns out, it’s not that easy to get the correct stack address when ASLR
kicks in.
Normally you would just leak __environ
and calculate the offset to the stack address, but this didn’t work at all in this challenge (not sure if it was due to pwnableharness
). The offset always differs, so no chance.
This took me way longer than expected, but after searching for a stack address anywhere
in despair, I opted to leak ld
, which contained a proper stack address.
This one remained stable even with ASLR
, so now we can prepare a fake page on the heap, together with a ropchain and trigger an unlink to overwrite the value for ecx
.
The first page just serves as a fake page (it isn’t referenced anywhere until now), which we can use for unlink
later on.
The last page just contains the ropchain, we want to execute later on.
And finally we’re using unlink
for something useful.
- Remove the current page
- Insert another page, overwriting the metadata of the previous page
- Flip to previous, so we’re in the page again, whose metadata we just overwrote
- Flip again to previous, to get into our fake page (whose
prev
is now pointing to thestack
).
Now removing this page, will trigger
finally writing the address of our ropchain chunk to the address, which will get popped into ecx
later on.
And there it goes, printing the pages, getting our heap address into ecx
, loading it into esp
, pivoting the stack on the heap, executing the ropchain.
We’ll just have to keep in mind, that the ropchain
page also gets malformed by the unlink, putting a stack address in it. Thus the pop4
gadget at the start, to get those out of the way.
esi
was also filled with crap, and one_gadget
wanted to have it point to rw
section of libc, so we’ll just set it manually and call one_gadget
.
I had to fix up some heap addresses when going remote, since addresses seemed to be off, but we can reuse the leak_addr
function for finding our payloads on heap again.
And finally, after all addresses were fixed up: