C: чтение большего количества байтов, чем форматная строка, с помощью инъекции форматной строки


В работе , использующей уязвимости форматных строк, авторы приводят следующий пример кода, где input - это некоторый нефильтрованный пользовательский ввод.

char outbuf[512];
char buffer[512];
sprintf (buffer, "ERR Wrong command: %400s", input);
sprintf (outbuf, buffer);

Затем они объясняют, что, используя специальную строку формата в качестве входных данных, они могут обойти ограничение %400s:

"%497dx3cxd3xffxbf<nops><shellcode>"

Это создает строку длиной 479 символов. Однако я не могу найти объяснения тому, как %479d обходит ограничение %400s. Как этот вход позволяет sprintf записать строку, которая является длиннее 400 символов?

2 4

2 ответа:

Второй sprintf() переполняет outbuf, потому что он использует строку формата, сгенерированную первым sprintf(), и размещение "%497d" в этой строке заставляет его печатать 497-char широкое целочисленное поле (дополненное пробелами, чтобы получить полную ширину). Это вместе с остальной частью этой строки превысит размер буфера 512-char outbuf. Это также заставит его попытаться прочитать целочисленный аргумент, который на самом деле не передается функции (2nd sprintf()).

Проблема заключается в том, что если input содержит маркеры %, то buffer будет содержать эти маркеры % (после первого sprintf()), а затем, используя второй sprintf(), "строка формата" будет buffer и маркеры % в ней будут интерпретированы, даже если нет аргументов для интерполяции в outbuf. Чтобы избежать этой проблемы:

snprintf(outbuf, sizeof(outbuf), "%s", buffer);

Или

strcpy(outbuf, buffer);

В этом контексте snprintf() является излишним, но он обнажает механизм до основ.