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

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

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

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

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

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

 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 . Вы можете прочитать данные исходной строки формата в 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 string (у Phrack есть некоторые, в основном, превосходные, хотя они могут быть немного продвинуты) или книга, затрагивающая эту тему.


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

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

 "%200$p" 

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

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


* Сокращения I18N, L10N, G11N и M18N предназначены для интернационализации, локализации, глобализации и мультинационализации соответственно. Число представляет количество пропущенных букв.

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

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

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

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

Взгляните на ссылки в этой статье; они выглядят интересными .

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

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

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

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

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


Обновить:

См. Эту ссылку для ошибки CSRSS, о которой я говорил.


Редактировать:

Обратите внимание, что чтение произвольных данных может быть столь же опасным, как выполнение произвольного кода! Если вы читаете пароль, cookie и т. Д., То это так же серьезно, как и выполнение произвольного кода – и это тривиально, если у вас достаточно времени, чтобы попробовать достаточно строк формата.

Давайте будем гением компьютера.