There are two ways to solve this problem. One is to pass the validation, and the other is to jump to execve. Since the first one is too time consuming, here I use the second one.
In function main, there is a alloca with random parameter, which will disturb the stack. So if we want to get information about the stack, we must leak it first.
In function fsb, there is a printf bug, and we can use %1$n to write any address. So we can just write an address, and use $ to get a reference, and we can write that address! However, all input is saved at .bss.
So we can consider another way. We can notice that the ebp is point to an old ebp, and we can control it.
First, we will let the old ebp point to function sleep in GOT(0x0804a008).ebp -> ori_ebp -> 0x0 becomes to ebp -> ori_ebp -> sleep_in_GOT.
And then, we try to leak the pointer that ebp point to, and the esp.
Finally, we just write the place that old ebp point to with address of evecve(0x080486ab).
And here is the step:
-
%134520840c%18$n(%18$is refer toebp) -
%18$x %14$x(%18$isebp,%14$ - 0x50isesp)Let's say the result is
a b. And the offset isr = a - b + 0x50 -
%34475c%r$hnwhichris calculated in the last step.
The result:
Wait a sec...
$ cat flag
Have you ever saw an example of utilizing [n] format character?? :(
PS: I found it not so hard to pass the validation since we can write anything, we can write the key! So we can just rewrite it to the value we are going to input.
Nice. You can actually accomplish this without computing any offsets. Take a look at where argument 14 points.