eis
eis

Reputation: 53482

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.

Upvotes: 2

Views: 1696

Answers (2)

jww
jww

Reputation: 102296

#define BUFFER_SIZE 4

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

There is another potential problem here if optimizations are enabled. buffer is 12 bytes, and its called as victim(buffer). Then, within victim, you try to copy 12 bytes into a 4 byte buffer with strcpy.

FORTIFY_SOURCES should cause the program to seg fault on the call to strcpy. If the compiler can deduce the destination buffer size (which it should in this case), then the compiler will replace strcpy with a "safer" version that includes the destination buffer size. If the bytes to copy exceeds the destination buffer size, then the "safer" strcpy will call abort().

To turn off FORTIFY_SOURCES, then compile with -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.

Upvotes: 0

Cyan
Cyan

Reputation: 13968

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.

Upvotes: 4

Related Questions