-1

I'm trying to give an example of how that stack works by presenting a working buffer overrun example to my colleagues at work. It's hard to find working modern day examples but I have one that works, the only problem is I don't understand it!

I think by providing a string longer than the buffer as a password it is overwriting the compare variable. The example said to provide a password of zzzzzzzzzzzz but I don't see how that turns a 1 to a 0.

Can anyone help?

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

#define PASSWORD "secret233"
#define BUFFER_SIZE 10

int check_pass(char *input)
{
    int compare = 1;
    char buffer[BUFFER_SIZE];

    compare = strcmp(input, PASSWORD);
    printf("[matched value]:%d\n", compare);

    strcpy(buffer, input);
    printf("[matched value]:%d\n", compare);

    return !compare;
}

main()
{
    int passed = 0;
    char input[1024];

    while (1) {
        printf("Enter password: ");
        scanf("%s", input);

        passed = check_pass(input);
        if (passed) {
            printf("--Password correct!\n");
            break;
        }
        else
            printf("--Wrong password. Try again.\n\n");
    }
}

 
  • Thanks, what I want to understand is why. – Stuart O'Grady Feb 23 '22 at 05:44
  • 3
    Perhaps run the code in a debugger and look at the stack and how it's arranged in memory? – Paul Hankin Feb 23 '22 at 06:57
  • Note that there's many unknowns in this example, including the specific compiler and system you're compiling on. To understand the behavior, you're going to need to know how the system you're using represents ints (typically 32 or 64 bits, big- or little-endian), and alignment. I guess a buffer of length 10 gets padded to 12 bytes (a multiple of 4 bytes), and "zzzzzzzzzzzz" is 12 bytes of z followed by a byte of 0, and that zero byte gets copied into `compare` (which is stored little-endian) so overwriting the non-zero value with a zero. – Paul Hankin Feb 23 '22 at 07:00
  • 2
    Note that none of this behavior is guaranteed, and in fact I'd expect a compiler with to optimize away all the code that reads/writes to `buffer` in `check_pass`. The compiler might also "know" that compare can't change, so for example have it stored in a register making the buffer over-run irrelevant. – Paul Hankin Feb 23 '22 at 07:05

1 Answers1

2

Best example of Buffer Overflow would be like this:

The following program obtains an input from the user and compare it with a password. That's fairly simple to demonstrate.

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

int main(void)
{
    char my_input[12];
    char my_password[12] = "password123";
    scanf("%s", my_input);

    if (strcmp(my_input, my_password) == 0)
        printf("PASS\n");
    else
        printf("ERROR\n");
    return 0;
}

Now, compile the above program like:

gcc main.c -o main

Then, type the following command:

./main < <(python -c "print('AAAAAAAAAAA' + '\x00' + 'AAAAAAAAAAA' + '\x00')")

Result would be:

PASS

Q: How did this happen?

ANS: scanf() function does not check for the length of the string, if it goes above a certain limit then it just overwrites the next stack stored variable. (my_password)

Q: How to fix this issue?

Ans: Use %<LIMIT>s instead of %s to prevent buffer overflow. OR Simply use fgets() function which is a lot better option.

So, your final code should be like:

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

int main(void)
{
    char my_input[12];
    char my_password[12] = "password123";
    scanf("%12s", my_input); // limit is now only 12

    if (strcmp(my_input, my_password) == 0)
        printf("PASS\n");
    else
        printf("ERROR\n");
    return 0;
}

Now re-run the above command:

./main < <(python -c "print('AAAAAAAAAAA' + '\x00' + 'AAAAAAAAAAA' + '\x00')")

Result:

ERROR
Darth-CodeX
  • 2,166
  • 1
  • 6
  • 23
  • 1
    This only works on systems where the compiler allocates `my_input` and `my_password` in the assumed order and with no gaps. However, a fine example where to start. – the busybee Feb 23 '22 at 08:51