cbuffer-overflowfortify-source

Buffer overflow example working on Windows, but not on Linux


In the book I am reading, Software Exorcism, has this example code for a buffer overflow:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 4

void victim(char *str)
{
        char buffer[BUFFER_SIZE];
        strcpy(buffer,str);
        return;
}

void redirected()
{
        printf("\tYou've been redirected!\n");
        exit(0);
        return;
}

void main()
{
        char buffer[]=
        {
                '1','2','3','4',
                '5','6','7','8',
                '\x0','\x0','\x0','\x0','\x0'
        };
        void *fptr;
        unsigned long *lptr;

        printf("buffer = %s\n", buffer);
        fptr = redirected;
        lptr = (unsigned long*)(&buffer[8]);
        *lptr = (unsigned long)fptr;

        printf("main()\n");
        victim(buffer);
        printf("main()\n");
        return;
}

I can get this to work in Windows with Visual Studio 2010 by specifying

With those compile options, I get this behavior when running:

buffer = 12345678
main()
        You've been redirected!

My question is about the code not working on Linux. Is there any clear reason why it is so?

Some info on what I've tried:

I've tried to run this with 32-bit Ubuntu 12.04 (downloaded from here), with these options:

[09/01/2014 11:46] root@ubuntu:/home/seed# sysctl -w kernel.randomize_va_space=0
kernel.randomize_va_space = 0

Getting:

[09/01/2014 12:03] seed@ubuntu:~$ gcc -fno-stack-protector -z execstack -o overflow overflow.c 
[09/01/2014 12:03] seed@ubuntu:~$ ./overflow
buffer = 12345678
main()
main()
Segmentation fault (core dumped)

And with 64-bit CentOS 6.0, with these options:

[root]# sysctl -w kernel.randomize_va_space=0
kernel.randomize_va_space = 0
[root]# sysctl -w kernel.exec-shield=0
kernel.exec-shield = 0

Getting:

[root]# gcc -fno-stack-protector -z execstack -o overflow overflow.c 
[root]# ./overflow
buffer = 12345678
main()
main()
[root]#

Is there something fundamentally different in Linux environment, which would cause the example not working, or am I missing something simple here?

Note: I've been through the related questions such as this one and this one, but haven't been able to find anything that would help on this. I don't think this is a duplicate of previous questions even though there are a lot of them.


Solution

  • Your example overflows the stack, a small and predictable memory layout, in an attempt to modify the return address of the function void victim(), which would then point to void redirected() instead of coming back to main().

    It works with Visual. But GCC is a different compiler, and can use some different stack allocation rule, making the exploit fail. C doesn't enforce a strict "stack memory layout", so compilers can make different choices.

    A good way to view this hypothesis is to test your code using MinGW (aka GCC for Windows), proving the behavior difference is not related strictly to the OS.