Causing a buffer Overflow with fgets

后端 未结 2 1978
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-11 15:11

I\'m experimenting with buffer overflows and try to overwrite the return address of the stack with a certain input of fgets

This is the code:

void fo         


        
相关标签:
2条回答
  • 2021-01-11 15:41

    You did not count with memory aligment. I changed the code a litte bit to make it easier to find the right spot.

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int **x;
    int z;
    
    void foo()
    {
        fprintf(stderr, "You did it.\n");
    }
    
    void bar()
    {
        char buf[2];
        //puts("Input:");
        //fgets(buf, 70, stdin);
        x = (int**) buf;
        for(z=0;z<8;z++)
                printf("%d X=%x\n", z, *(x+z));
        *(x+3) = foo;
        printf("Your input: %d %s\n", strlen(buf), buf);
    }
    
    
    int main(int argc, char **argv)
    {
            printf("Foo: %x\n", foo);
            printf("Main: %x\n", main);
            bar();
            return 0;
    }
    

    With a smaller buffer, 2 in my example, I found the return address 24 bytes away (x+3, for 8 byte pointers; 64 bits, no debug, no optimization...) from the beginning of the buffer. This position can change depending on the buffer size, architecture, etc. In this example, I manage to change the return address of bar to foo. Anyway you will get a segmentation fault at foo return, as it was not properly set to return to main.

    I added x and z as global vars to not change the stack size of bar. The code will display an array of pointer like values, starting at buf[0]. In my case, I found the address in main in the position 3. That's why the final code has *(x+3) = foo. As I said, this position can change depending on compilation options, machine etc. To find the correct position, find the address of main (printed before calling bar) on the address list.

    It is important to note that I said address in main, not the address of main, bacause the return address was set to the line after the call to bar and not to the beginning of main. So, in my case, it was 0x4006af instead of 0x400668.

    In your example, with 20 bytes buffer, as far as I know, it was aligned to 32 bytes (0x20).

    If you want to do the same with fgets, you have to figure out how to type the address of foo, but if you are running a x86/x64 machine, remember to add it in little enddian. You can change the code to display the values byte per byte, so you can get them in the right order and type them using ALT+number. Remember that the numbers you type while holding ALT are decimal numbers. Some terminals won't be friendly handling 0x00.

    My output looks like:

    $ gcc test.c -o test
    test.c: In function ‘bar’:
    test.c:21: warning: assignment from incompatible pointer type
    $ ./test
    Foo: 400594
    Main: 400668
    0 X=9560e9f0
    1 X=95821188
    2 X=889350f0
    3 X=4006af
    4 X=889351d8
    5 X=0
    6 X=0
    7 X=95a1ed1d
    Your input: 5 ▒▒`▒9
    You did it.
    Segmentation fault
    
    0 讨论(0)
  • 2021-01-11 15:42
    void bar()
    {
        char buf[20];
        puts("Input:");
        fgets(buf, 24, stdin);
        printf("Your input:.\n", strlen(buf));
    }
    

    ... This works and causes a segmentation fault...

    The compiler is probably replacing fgets with a safer variant that includes a check on the destination buffer size. If the check fails, the the prgram unconditionally calls abort().

    In this particular case, you should compile the program with -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.

    0 讨论(0)
提交回复
热议问题