Злоумышленник всегда сможет определить, откуда из стека функция printf() считывает свой параметр, соответствующий спецификации преобразования %n. Используя такие спецификации формата, как, например, %x или %p, он может воспользоваться функцией printf() для перемещения по стеку до адреса, помещенного злоумышленником в стек. Предполагая, что при записи в стек данные пользователя не обрезались, злоумышленник с помощью функции printf() сможет считывать данные из стека до тех пор, пока не доберется до нужного ему адреса в стеке. После этого останется только разместить в форматирующей строке спецификацию преобразования %n для записи данных по адресу, заданному злоумышленником.
...
Примечание
Если в форматирующую строку помещен адрес, то в нем не должно быть никаких нулевых байтов, за исключением последнего. Любой нулевой байт в форматирующей строке воспринимается как признак конца строки, поскольку любая строка в языке C является массивом символов, признаком окончания которого служит нулевой байт. Это не означает, что адреса, содержащие нулевые байты, никогда не могут использоваться. Часто адреса помещаются в стек отдельно от форматирующей строки. В этих случаях злоумышленник может записывать данные в область памяти, в адресе которой содержатся нулевые байты.
Например, если злоумышленник захочет использовать адрес из стека, хранящийся в 32 байтах от первого параметра функции printf(), то он должен определить в своей форматирующей строке 8 спецификаций преобразования %x. Спецификация преобразования %x – это спецификация вывода шестнадцатеричного целого числа без знака длиной в слово. На 32-разрядной платформе Intel длина слова равна 4 байтам. Каждый раз, встречая в форматирующей строке спецификацию преобразования %x, функция printf() считывает из стека очередные четыре байта, в которых хранится переменная, соответствующая найденной спецификации. Кроме рассмотренной, для чтения данных из стека можно воспользоваться и другими спецификациями преобразования, а для записи данных в нужную область памяти существует спецификация преобразования %n.
После нахождения нужного злоумышленнику адреса он может быть указан как значение переменной, соответствующей спецификации преобразования %n. В результате в область памяти по указанному адресу будет записано количество символов отформатированной строки. Если найденный адрес правильный и память доступна для записи, то старое содержимое найденной области памяти будет перезаписано.
Построение величин
Перед записью в память злоумышленник может прибегнуть к различным ухищрениям для получения нужного значения записываемой переменной целого типа. Для этого он может задать в спецификации преобразования ширину выводимого поля, увеличивая число символов в отформатированной строке.
int main()
{
// test.c
printf(“start: %10i end\n”,10);
}
В предыдущем примере форматирующая строка содержит спецификацию преобразования %10i — спецификацию вывода десятичного числа со знаком с заданной шириной поля, равной 10. Ширина поля указывает функции printf() использовать для вывода целого числа со знаком поле в отформатированной строке, достаточное для печати не менее 10 символов.
[dma@victim server]$ ./teststart: 10 end
Для десятичного представления числа 10 не требуется десяти символов, поэтому по умолчанию оставшаяся часть поля заполняется пробелами. Этим свойством функции printf() может воспользоваться злоумышленник для увеличения значения величины, записываемой в указанную область памяти при помощи спецификации преобразования %n без фактического увеличения размера отформатированной строки. Хотя при использовании в спецификации преобразования ширины поля можно записать в память достаточно большое число, тем не менее злоумышленнику для записи могут потребоваться еще большие числа.
Применив способ многократной записи с несколькими спецификациями преобразования %n, злоумышленник может использовать младшие значащие разряды получающихся по спецификации %n целых величин для раздельной записи каждого байта нужного ему числа. Этот прием позволяет получить нужные адреса памяти при относительно небольшом количестве спецификаций преобразования %n. Для реализации способа следует указать для каждой операции записи адрес, куда записывать, причем каждый последующий адрес смещается относительно первого на 1 байт.
Читать дальше
Конец ознакомительного отрывка
Купить книгу