1

Here is the my C++ program in which buffer overflow happened, still the local variable is not corrupted:

#include <iostream>
#include <cstring>

using namespace std;

int main() {
    // your code goes here
    int i = 20;
    char var[4];

    strcpy(var, "biiiiiiiyee");
    cout<<" var is : "<< var << endl;
    cout<<" i : " << i << endl;
    return 0;
}

The output of program is :

 var is : biiiiiiiyee
 i : 20

The assumption is that overwriting past the end of the var buffer should corrupt the i variable.

In the above program I'm overwriting the buffer, still the local variable did not corrected. Why?

2

Alignment. The compiler is allowed to place local variables on the stack in a way that the alignment to the CPU words is better. In other words, there is nothing that forces the compiler to place local variables one after another on the stack. Actually placing local variables one after another would be saving a couple of bytes in program size for a considerably big penalty in processing time.

Allow me to use plain C instead of C++ to explain 'cause it is much easier to drop it into GDB. Program converted to plain C, let's call is pp.c:

#include <stdio.h>
#include <string.h>

int main() {
    int i = 20;
    char var[4];

    strcpy(var, "12345678901");
    printf(" var is : %s\n", var);
    printf(" i : %d\n", i);
    return 0;
}

Note that the string I used is of the same length:

"12345678901"
"biiiiiiiyee"

Let's compile it without optimizations, just in case:

gcc -O0 -g -o pp pp.c

And now let's look at the program running:

$ gdb -q pp
Reading symbols from pp...done.
(gdb) list
1   #include <stdio.h>
2   #include <string.h>
3   
4   int main() {
5       int i = 20;
6       char var[4];
7   
8       strcpy(var, "12345678901");
9       printf(" var is : %s\n", var);
10      printf(" i : %d\n", i);
(gdb) break 8
Breakpoint 1 at 0x4004fa: file pp.c, line 8.
(gdb) break 9
Breakpoint 2 at 0x400510: file pp.c, line 9.
(gdb) run
Starting program: /home/grochmal/tmp/pp 

Breakpoint 1, main () at pp.c:8
8       strcpy(var, "12345678901");

OK we are just before the overflow happens, let's see where the stack is and where the variables on the stack are:

(gdb) p $rsp
$1 = (void *) 0x7fffffffe860
(gdb) x/16x 0x7fffffffe860
0x7fffffffe860: 0xffffe950  0x00007fff  0x00000000  0x00000014
0x7fffffffe870: 0x00400550  0x00000000  0xf7a5c291  0x00007fff
0x7fffffffe880: 0xf7dd0798  0x00007fff  0xffffe958  0x00007fff
0x7fffffffe890: 0xf7b9cc48  0x00000001  0x004004f6  0x00000000
(gdb) p &var
$2 = (char (*)[4]) 0x7fffffffe860

Very good, var is really at the top of the stack (0x7fffffffe860) but i is not 4 bytes later. i is at 0x7fffffffe86c, 12 bytes later (i is 20, i.e. 0x00000014). Let's see what happens next:

(gdb) cont
Continuing.

Breakpoint 2, main () at pp.c:9
9       printf(" var is : %s\n", var);
(gdb) x/16x 0x7fffffffe860
0x7fffffffe860: 0x34333231  0x38373635  0x00313039  0x00000014
0x7fffffffe870: 0x00400550  0x00000000  0xf7a5c291  0x00007fff
0x7fffffffe880: 0xf7dd0798  0x00007fff  0xffffe958  0x00007fff
0x7fffffffe890: 0xf7b9cc48  0x00000001  0x004004f6  0x00000000

The buffer does overflow! But not far enough, we need 1 extra byte (remember that that 0x00 is the null terminator) to reach the place in memory where i is located. If we change our strcpy to:

strcpy(var, "AAAAAAAAAAAA\x39\05\x00");

You get to overwrite i:

$ gcc -O0 -g -o pp pp.c
$ ./pp
 var is : AAAAAAAAAAAA9
 i : 1337

It is not easy to guess alignment, it depends on CPU and compiler. Most (white/gray/black) hats do it by trial and error, or by compiling the program in the same environment it is run and then looking at it in a debugger (as we did above).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.