ELF x86 — Format string bug basic 2 Rootme (App-System)[Changing values using Format String vulnerability]
This is a Medium level challenge from Rootme that uses the format string vulnerability to get the flag. Format strings are not only used to display the stack data but also write data anywhere on the stack.
The source code for the challenge has been given which makes our life a lot easier.
Let’s start analyzing the code. The binary takes the input via argument. The variable check is initialized to a value “0x04030201”. Then there is a memset happening. For the newbs out there memset is used fill to a block of memory with a particular value. and these are the parameters it takes in.
void *memset(void *Addr, int Val, size_t T);
Addr is the starting address of memory to be filled, Here fmt is the pointer variable used.
Val is the actual value to be filled, Here we use 0 to fill up the memory.
T is the number of bytes to be filled starting from Addr.
Next, we have two printf() functions to tell us where the check variable is located and what input we have given. Note that the ASLR is off in the actual Rootme machine, the check address is always the same. But if you download the binary in your machine the address changes randomly.
Then we have the actual vulnerable part “sprintf()”. This is where we can see the stack address and value by using format specifiers. Let us check by sending a few format specifiers.
If you noticed something familiar Congrats, you have an eagle eye. The last value which is printed is the value of the check variable.
Now on further analyzing the code, if check = 0xdeadbeef, We can pop the shell and get our flag.
Now, we need to check if the data we give in the input is stored somewhere in the stack. To do that I give some bunch of characters and see if the data is printed when I print stack values with format specifiers.
We can now control the values on the stack from the 9th argument. And that’s where the format specifier “%n” comes into action. “%n” can be used to write the value to a specific address. It causes printf() to write the variable pointed by the argument we specify. The writing is done with a value that is equal to the number of characters printed by printf() before the occurrence of %n.
We have the address to the variable “check” and “0xdeadbeef” is the value that needs to be loaded in the variable. 0xdeadbeef is 3735928559 in decimals. As loading is done with a value equal to the number of characters printed by printf function, We need to give (3735928559–4) =3735928555 spaces ( — 4 because the address we specify is 4 bytes here).
But the problems arise here. 3735928555 is very huge and cannot be used here. We need to split the writing of data into 2 parts. Again there is a way to do this with %hn format specifier. First, we write 0xbeef into the correct address followed by 0xdead. Now, this is where we need to do some maths. We split the address like this.
First, we load 0xbeef followed by 0xdead as we have the address loaded in little-endian format.
Now we split up our payload and write it in a way such that the characters before the %hn make 0xdead and 0xbeef. Note that the address we give also counts as characters. As we split up into 2 addresses, We have 4+ 4= 8 bytes of characters already in our printf. Keeping this in mind we need to construct the number of spaces required before each %hn.
CONSTRUCTING THE PAYLOAD
0xbeef = 48879 , 0xdead = 57005 in decimal
Address1 (4 bytes) + “Address2 (4 bytes)” + “%(48879–8 = 48871)x” (Gives that many spaces due to formatting) + “$9%hn” (We have 48879 bytes of spaces before first %hn, so this will give the value 0xbeef in the first address we specify) + “%(57005–48879 = 8126 )x” (As we already gave 48879 spaces previously, that is also counted ) + “%10$hn” (This will give 57005 spaces before second %hn, so this will give the value 0xdead in the second address we specify).
Let’s construct this in python.
For me, the check variable address was at “0xbffffa88”. It does change often. Also, don’t forget to add a \ before $ like this “%9\$hn” as $ symbol in Linux has a different meaning. Putting a “\” in front of $ will print the symbol as it is.
And there we go! We have our flag.
Hope you understood the challenge. Do check out my other blogs.
Don’t forget to give some claps if you reached here :) Follow me for more write-ups.