Как можно использовать уязвимость Format-String?

Я читал об уязвимостях в коде и наткнулся на это Уязвимость Format-String.

Википедия говорит:

ошибки строки формата наиболее часто появляются, когда программист хочет печать строки, содержащей данные, предоставленные пользователем. Программист может ошибочно напишите printf (buffer) вместо printf ("%s", buffer). Этот первая версия интерпретирует буфер как строку формата и анализирует любые форматирование инструкции он может содержать. Вторая версия просто выводит строку на экран, как и предполагал программист.

У меня возникла проблема с версией printf (buffer), но я все еще не понял, как эта уязвимость может быть использована злоумышленником для выполнения вредоносного кода. Может кто-то пожалуйста, скажите мне, как эта уязвимость может быть эксплуатируется пример?

5 ответов


вы можете использовать уязвимость строки формата многими способами, прямо или косвенно. Давайте используем следующее в качестве примера (при условии отсутствия соответствующей защиты ОС, что очень редко в любом случае):

int main(int argc, char **argv)
{
    char text[1024];
    static int some_value = -72;

    strcpy(text, argv[1]); /* ignore the buffer overflow here */

    printf("This is how you print correctly:\n");
    printf("%s", text);
    printf("This is how not to print:\n");
    printf(text);

    printf("some_value @ 0x%08x = %d [0x%08x]", &some_value, some_value, some_value);
    return(0);
}

основой этой уязвимости является поведение функций с переменными аргументами. Функция, которая реализует обработку переменного числа параметров, должна считывать их из стека, по существу. Если мы зададим строку формата, которая сделает printf() ожидайте два целых числа в стеке, и мы предоставляем только один параметр, второй должен быть чем-то другим в стеке. По расширению, и если у нас есть контроль над строкой формата, мы можем иметь два самых фундаментальных примитива:


чтение из произвольных адресов памяти

[EDIT] важно: я делаю некоторые предположения о макете фрейма стека здесь. Вы можете игнорировать их, если вы понимаете, основным условием уязвимость, и они варьируются в зависимости от ОС, платформы, программы и конфигурации в любом случае.

можно использовать %s format параметр для чтения данных. Вы можете прочитать данные строки исходного формата в printf(text), следовательно, вы можете использовать его для чтения чего-либо из стека:

./vulnerable AAAA%08x.%08x.%08x.%08x
This is how you print correctly:
AAAA%08x.%08x.%08x.%08x
This is how not to print:
AAAA.XXXXXXXX.XXXXXXXX.XXXXXXXX.41414141
some_value @ 0x08049794 = -72 [0xffffffb8]

запись на произвольные адреса памяти

можно использовать %n спецификатор формата для записи на произвольный адрес (почти). Опять же, давайте предположим, что уязвимая программа выше, и давайте попробуем изменить значение some_value, который расположен на 0x08049794, как показано выше:

./vulnerable $(printf "\x94\x97\x04\x08")%08x.%08x.%08x.%n
This is how you print correctly:
??%08x.%08x.%08x.%n
This is how not to print:
??XXXXXXXX.XXXXXXXX.XXXXXXXX.
some_value @ 0x08049794 = 31 [0x0000001f]

мы перезаписаны some_value С количеством байтов, написанных перед %n спецификатор был обнаружен (man printf). Мы можем использовать саму строку формата или ширину поля для управления этим значением:

./vulnerable $(printf "\x94\x97\x04\x08")%x%x%x%n
This is how you print correctly:
??%x%x%x%n
This is how not to print:
??XXXXXXXXXXXXXXXXXXXXXXXX
some_value @ 0x08049794 = 21 [0x00000015]

есть много возможностей и трюков, чтобы попробовать (прямой доступ к параметру, большая ширина поля, что делает возможным обертывание, строительство ваши собственные примитивы), и это просто касается вершины айсберга. Я бы предложил прочитать больше статей об уязвимостях строки fmt (Phrack имеет некоторые в основном отличные, хотя они могут быть немного продвинутыми) или книгу, которая затрагивает эту тему.


отказ от ответственности: примеры взяты [хотя и не дословно] из книги хакинг: искусство эксплуатации (2-е изд) Джон Эриксон.


интересно, что никто не упомянул n$ нотация, поддерживаемая POSIX. Если вы можете управлять строкой формата в качестве атакующего, вы можете использовать такие обозначения, как:

"%200$p"

читать 200th элемент в стеке (если он есть). Намерение состоит в том, что вы должны перечислить все n$ числа от 1 до максимума, и это обеспечивает способ перестановки параметров в строке формата, что удобно при работе с I18N (L10N, G11N, M18N*).

однако некоторые (вероятно, большинство) систем несколько апатичны о том, как они проверяют n$ значения и это может привести к злоупотреблению злоумышленниками, которые могут управлять строке формата. В сочетании с %n спецификатор формата, это может привести к записи в местах указателя.


* аббревиатуры с названием i18n, команде l10n, G11N и M18N для интернационализации, локализации, глобализации, и multinationalization соответственно. Число представляет собой количество пропущенных букв.


Ах, ответ в статье!

неконтролируемая строка формата - это тип уязвимости программного обеспечения, обнаруженный около 1999 года, который может использоваться в эксплойтах безопасности. Ранее считалось безвредным, format string exploits можно использовать для сбой программы или выполнить вредоносный код.

типичный эксплойт использует комбинацию этих методов, чтобы заставить программу перезаписать адрес библиотечной функции или обратный адрес в стеке с указателем на какой-то вредоносный шеллкод. Параметры заполнения для спецификаторов формата используются для управления количеством байтов вывода и %x токен используется для вывода байтов из стека до тех пор, пока не будет достигнуто начало самой строки формата. Начало строки формата создается, чтобы содержать адрес, который на %n маркер формата может затем перезаписать адрес вредоносного кода для выполнения.

этот потому что %n причины printf to написать данные в переменную, которое находится в стеке. Но это означает, что он мог написать что угодно. Все, что вам нужно, это чтобы кто-то использовал эту переменную (это относительно легко, если это указатель функции, значение которого вы только что выяснили, как управлять), и они могут заставить вас выполнять что-либо произвольно.

взгляните на ссылки в статье; они посмотреть интересно!--26-->.


Я бы рекомендовал читать этой лекция об уязвимости строки формата. Он подробно описывает, что происходит и как, и имеет некоторые изображения, которые могут помочь вам понять тему.


AFAIK это в основном потому, что это может привести к сбою вашей программы, которая считается атакой отказа в обслуживании. Все, что вам нужно, это дать недопустимый адрес (практически что-нибудь несколько %sгарантированно работает), и это становится простой атакой отказа в обслуживании (DoS).

теперь, это теоретически возможно для этого, чтобы вызвать что-либо в случае обработчика исключений/сигналов/прерываний, но выяснить, как это сделать, вне меня -- вам нужно выяснить, как написать произвольные данные в память.

но почему кого-то волнует, если программа аварийно завершает работу, вы можете спросить? Разве это не просто неудобство для пользователя(кто этого заслуживает)?

проблема в том, что некоторые программы доступны нескольким пользователям, поэтому сбой их имеет несущественную стоимость. Или иногда они имеют решающее значение для работы системы (или, возможно, они находятся в середине чего-то очень важного), в котором случай это может повредить вашим данным. Конечно, если вы разбиваете Блокнот, то никто не может заботиться, но если вы разбиваете CSRSS (который, я считаю, на самом деле имел похожую ошибку-двойную бесплатную ошибку, в частности), то да, вся система идет вниз с вами.


обновление:

посмотреть этой ссылке для ошибки CSRSS, о которой я говорил.


Edit:

обратите внимание, что читать произвольные данные могут быть опасно!--3--> как выполнение произвольного кода! Если Вы читаете пароль, cookie и т. д. тогда это так же серьезно, как произвольное выполнение кода, - и это тривиальные если у вас достаточно времени, чтобы попробовать достаточно строк формата.