...

Инструментарий и ловушки

Больше стека меньшей форматирующей строкой

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

Идея заключается в том, чтобы с помощью функции printf() по указанным адресам прочитать больше данных, передав функции сравнительно небольшую форматирующую строку. Для этого существует несколько способов.

Использование типов данных, требующих для своего размещения области памяти большего размера. Первое, что приходит на ум, – это использовать спецификации формата, которые для представления обрабатываемых данных используют поля большего размера. Другими словами, эти спецификации соответствуют более длинным данным. Одной из них является спецификация формата %lli, которая соответствует сверхдлинному целому числу (типу данных long long integer). В случае ее использования на 32-разрядной архитектуре Intel функция printf() будет читать из стека очередные 8 байт при обработке каждой спецификации формата %lli форматирующей строки. Точно так же можно использовать спецификацию вывода длинного числа с плавающей точкой (long float) или длинных чисел с плавающей точкой двойной точности (double long float). Но следует иметь в виду, что при использовании этих спецификаций преобразования неверные данные стека могут привести к аварийному завершению программы из-за ошибок операций с плавающей точкой.

Использование длины выводимого аргумента. Некоторые версии библиотеки libc поддерживают в спецификации формата символ *. Символ * сообщает функции printf(), что ширина поля вывода, соответствующего этой спецификации формата, задается параметром функции printf(), который при вызове функции был записан в стек. Использование символов * приводит к тому, что для каждого из них в стеке будет дополнительно выделено 4 байта. Ширина поля вывода, записанная в стек, может быть отменена, если за символами * указать число. Например, использование спецификации преобразования %*******10i приведет к тому, что для представления целого числа будет использовано 10 символов. Но при обработке спецификации преобразования %*******10i функция printf() все равно прочтет из стека 32 байта. Считается, что первым этот способ применил автор, известный под псевдонимом lorian.

Непосредственный доступ к параметрам. В ряде случаев возможен непосредственный доступ к параметрам функции printf(). Для этого применяется спецификация преобразования вида %$xn, где x – порядковый номер параметра при вызове функции printf().

Этот способ применим только в библиотеках языка C, которые поддерживают непосредственный доступ к параметрам.

Если перечисленные уловки не помогли злоумышленнику добраться до нужного ему адреса, то он может попытаться найти любую другую доступную область стека, куда могли быть помещены нужные адреса памяти. Помните, что совсем необязательно нужные адреса связаны с форматирующей строкой. Иногда бывает удобным разместить их в соседнюю со стеком область данных. Для злоумышленника могут оказаться полезными входные данные программы, не связанные с форматирующей строкой. Уязвимость утилиты Screen проявилась в том, что в большинстве случаев злоумышленник мог получить доступ к данным, определенным переменной окружения HOME. Эти данные располагались ближе других к стеку, поэтому их легче было найти и воспользоваться ими.

Загрузка...