So, in this challenge we have a little echo service.
But since we’re marked as a guest we’re only allowed to use the guestecho:
There’s also a rootecho which only differs in the amount of read bytes:
While we cannot do much mischief with the guestecho function, the rootecho function would allow us to do a buffer overflow.
So, first let’s find out, how to get root:
The password is generated from /dev/urandom, so don’t even try guessing it.
So, the IS_GUEST variable is stored 32 bytes behind the username and is set to 1 if we’re not admin. Since IS_GUEST is set, after we entered the username, we won’t be able to change it here.
But there is also a change_username function:
So, it reads 32 bytes again for the username and then strcpys it to the user variable.
But if we enter exactly 32 bytes, strcpy will copy the string together with the following null-terminator into user, and since IS_GUEST is exactly at user+32 it will be overwritten with the null-terminator (effectively setting it to 0).
So, now that we can use rootecho it’s time for ropping… Oh well, there’s still a canary to defeat, before we really can do something.
Since canaries end/start with a null byte, we cannot just align our input with the canary but have to partial overwrite it (otherwise our output would just stop before that null byte).
While overwriting the canary would mostly crash the application, we’re lucky here, that the rootecho function doesn’t return until we enter exit.
So, we can overwrite the lowest byte of the canary (we know, that it’s \x00, so that’s no problem) and echo it.
Since we’re still in the rootecho function, we can now repair the canary again and write a ropchain before leaving it.
But since ASLR is active, we don’t know any good addresses to rop to, so we need to leak libc in the first stage:
Didn’t find an easy way to set r0 for calling puts, so I used multiple gadgets to fill r0.
This ropchain will first put puts plt into r3 and then call the second pop gadget, which will fill r4 to r8 and then call
mov r0, r7; blx r3
Since we wrote e.got["puts"] to r7, this will write puts got to r0 and then call r3 (pointing to puts plt), thus printing puts got.
With this we can calculate the libc address and start the second stage executing something useful.
We’ll just use the same gadgets to execute system("/bin/sh"):
This time we’ll write system to r3, which will gets executed after our pop gadgets.
In the pop gadgets we’ll store the address of /bin/sh to r7=>r0, resulting in calling system("/bin/sh") when we exit the rootecho function.