C - Why is this program insecure?

Viewed 383

I have homework in which I am supposed to analyze this C program and answer three questions. This is the program:

int main()
{
    // Define buffers to store username and password
    char username[16];
    char password[16];
    // Read username and password from user input
    printf("Enter your name: ");
    scanf("%s", username);
    printf("Enter your password: ");
    scanf("%s", password);
    printf("[SHOUTING OUT LOUD] Hello, %s!\n", username);
    return 0;
}

These are the questions:

  1. There is a security hole which makes it possible that the password will be printed. How is this possible?
  2. How can it be achieved that the program crashes?
  3. Correct the program so that there are no security holes anymore.

I think that the problem lies in the scanf method because the amount of characters which can be scanned is not limited. So I think by inputting a long string it is possible to get a segmentation fault because you want to save the characters in memory which must not be referenced by the user. This would be my answer for 2. The answer for 3 is that the program can be corrected by limiting the number of characters which can be scanned. But I don't seem to find an answer for 1. Could you help me out with this one?

2 Answers

Imagine if the implementation stores the username and password consecutively in memory. It's vital that the print statement stop before it outputs the password. But it will only do this if it encounters a zero byte inside the username field. If the username is too long, there will be no zero byte in the username field, so the print could continue outputting the contents of the password field.

Your scanf calls do not limit the number of bytes the user may enter.

A carefully crafted input could allow arbitrary execution of code because the string could overwrite the return address on the stack, inject arbitrary code, etc.

The injected code could examine the stack frame memory left over after the return and print the password.

The password stays in memory at the address on the stack assigned during the [legit] call to main for the password variable. After main returns, the password value is still there in the memory (i.e. it's not cleared)

This requires that the injected code not do stack operations that change the left over memory. Difficult, but not impossible.

To fix, try (e.g.):

scanf("%15s",username);

Another thing to consider is that, normally, information input via scanf is echoed by the TTY driver.

This is what we'd want for getting username. But, we'd want to disable echo in the TTY layer before the scanf for password.

We'd need to do something like tcgetattr and tcsetattr to effect this.

But, if we do that, it's tricky to get this to work with scanf. So, we should switch to pure read(0,buf,1) calls (e.g.)

Related