ISITDTU CTF 2018 Quals - babyformat
8 Solves
nc 104.196.99.62 2222
Attachment: babyformat libc.so.6 xpl.py
From the name it’s already quite obvious, that we’ve got a format string challenge here.
Let’s quickly wrap up the code in the binary
Ok, pretty obvious format string vulnerability, though the buffer for the format string is not located on the stack but in the bss
. Thus, we cannot reuse any of our input for the format string exploit (like adding addresses in the format string itself) and can only work with values already on the stack.
Also there’s a COUNT
variable, which only allows us to send 3 input strings.
To exploit this successfully, we need to
- change count to get infinite writes
- prepare a stack writer to write arbitrary values into the stack
- identify the remote libc
- write a simple ret2libc ropchain
If we’re able to write arbitrary addresses into the stack, the other stuff won’t be a big problem anymore. But before being able to do anything useful, we need to either modify COUNT
or change the counter variable i
.
I went for the latter and we’ll use up all 3 attempts for this.
First, some global leaks for pie and stack:
The 9th format string parameter contains the address of parameter 57:
We can use this, to modify the lower word of the address parameter 57 is pointing to, to let it point to some other value on the stack (high word will be the same, so we don’t need to modify it).
Thus, we first change the address for parameter 57 to point it to i
In fact, we write the address of i
+ 3 there, to let it point to the highest byte, so we only have to write one byte to make it negative
This was the third write, so i
should have a value of 3
, but after our last write it will now be 0xff000003 (-16777213)
, which should give us more than enough tries :)
Now to the next part, for being able to write arbitrary values on the stack (and not only modifying existing stack variables), we need to be able to write the hi
and lo
word of an address. To get to this point, we’ll first prepare two stack writer addresses
, which will show to the lo
and hi
word portion of another stack address.
Again, parameter 9
holds the address for parameter 57
, and parameter 10
holds the address for parameter 59
.
With this our stack will look like this
(I suck at drawing arrows :P)
Parameter 9 points to 0xffffd754
and Parameter 10 points to 0xffffd57c
and we just filled 0xffffd754
(57) with the (lo
) address of parameter 61 (0xffffd584
) and 0xffffd57c
(59) with the address of the hi
word of parameter 61 (0xffffd586
).
From now on, we can use 57 and 59 to change the hi and lo word of parameter 61, and then use parameter 61 to write a value to this address.
So we can now already write a word to an arbitrary address. By just using this mechanism again to also write to the hi word address, we have an arbitrary write function :)
So, we now have arbitrary write via write_value
. From here on it should be an easy game.
We can use this to write a ropchain to the return address and then trigger it, by leaving with EXIT
. Though we only know pie and stack addresses at the moment, so we need to identify the remote libc first.
Let’s just use a ropchain to leak some got entries from the remote system (this won’t be used in the final exploit).
With this, we can leak multiple got entries from the remote system, and use for example libc-database from niklasb
to identify the used libc.
Armed with the correct libc, we can now change our leak-ropchain into a system("/bin/sh")
ropchain and finish this.
for leaking and calculating libc base address and then finally
You’ll see a lot of r.interactive()
here.
The remote system will send a lot of whitespaces back to us, and it’s important that the buffers are cleared, when doing the next write.
It’s possible to do this in a cleaner way, by receiving the correct amount of whitespaces before doing the next write, but just adding a r.interactive()
is the cheap way of getting around this, so you’ll just have to press CTRL+C
some times until you arrive at the last pause (which will then trigger the shell).