2
votes
#include  <stdio.h>

int main()
{
    char buf[100];
    char s[100];
    int x = 1;
    fgets(s, 100, stdin);
    snprintf(buf, sizeof buf, s);
    printf("Buffer size is: (%d) \nData input: %s \n", strlen(buf), buf );
    printf("X equals: %d/ in hex: %x\nMemory address for x: (%p) \n", x, x, &x);
    return 0;
}

When I run this simple c program, the program begins executing, waits for stdin input, and then executes the print statements.

Everything works as expected normally, but when I enter '%n' to stdin, I receive:

*** %n in writable segment detected ***
Aborted

What is happening, and why is this input to fgets() causing this?

1
snprintf(buf, sizeof buf, "%n"); without further argument... the last argument is the format. you have to specify more arguments. - Jean-François Fabre
Looks like an exploit tactic. - Weather Vane
It isn't the fgets. It's the snprintf. There s is interpreted as a format string. Try snprintf(buf,sizeof buf,"%s",s) instead - Craig Estey

1 Answers

0
votes

from https://linux.die.net/man/3/snprintf:

Code such as printf(foo); often indicates a bug, since foo may contain a % character. If foo comes from untrusted user input, it may contain %n, causing the printf() call to write to memory and creating a security hole.

The third argument to snprintf is the format string (which is the same case as above).

Letting the user input a format specifier (specially %n, see What is the use of the %n format specifier in C?) opens your program to a security hole. Here the program reads some garbage value in memory (since no further argument is specified) and writes to it, that's why %n is particularly dangerous (here it seems that it was intercepted before writing to the memory by the C library, nice feature)

As Craig commented, always use your format string to process user input:

snprintf(buf,sizeof buf,"%s",s)