The binary greets us with a prompt, and seems to not really react to any input…
Ok, makes more sense now.
If we enter 11010110 it will enter the leak function. On 10110101 it will enter ccloud.
Leaks are always good, so let’s check this first :)
This will loop until we enter 11111111 and always read 0x128 bytes into buf and print it.
buf was initiaized in main with
so there still might be some interesting addresses in it.
We can leak all those addresses by aligning buf next to them
We can just grab the libc from the cat challenge, most probably the same (and yes, it is).
We’ll then leave the leak block and enter the ccloud block
Hmmm, everything seems fine. Allocating a buffer, reading to it and putting a null terminator at the end of the string. And then the binary will directly free the buffer again.
What can we do with this? Well, at first, not much…
As long, as we serve malloc valid sizes, everything will just run fine. But what will happen, if we enter an invalid size?
malloc will fail and return 0x0.
is equivalent to
If we enter something like 0 as size, this will segfault, because it won’t be able to dereference 0x0 and thus crash.
But what happens, if we pass a size of -0xffff80000822e6e7? malloc will also fail…
But 0 + (-0xffff80000822e6e7) - 1 evaluates to 0x7ffff7dd1918, thus writing a NULL byte to 0x7ffff7dd1918.
We can abuse this to write a NULL byte to an arbitrary address. Just where… Where can a single NULL byte do any good?
This little snippet happens to be stdin. _IO_buf_base and _IO_buf_end will be used by scanf to store its input to.
If we’d overwrite the LSB of _IO_buf_base with a 0x0 it would now point to _IO_write_base (0x7ffff7dd1900).
Thus, everything we would now pass to scanf, would overwrite the data at 0x7ffff7dd1900 with which we could write arbitrary pointers to _IO_buf_base and _IO_buf_end, which enables us to write data to an arbitrary address :)
Let’s prepare this
This overwrites the LSB of _IO_write_base.
With this payload we’ll now overwrite _IO_buf_base with an address near free_hook, which enables us in the next write to overwrite free_hook itself.
Since the loop in ccloud will now immediately free our buffer, it will trigger the one_gadget, we just put into free_hook, resulting in a shell :)