В этой главе приведены начальные сведения об ошибках форматирующей строки, причины их возникновения и способы их использования в злонамеренных целях. Будет рассмотрена реальная уязвимость форматирующей строки и показано, как злоумышленник может ей воспользоваться.
Уязвимость форматирующей строки
Для понимания сути уязвимости форматирующей строки необходимо иметь четкие представления о работе функции printf().
Часто программистам требуется сформировать строку из нескольких переменных разного типа во время работы программы. Зачастую при разработке программы точное количество переменных, необходимых для формирования строки, и порядок их следования неизвестны. В основном для этих целей используется семейство функций printf, предоставляющее гибкие возможности создания и форматирования строк во время выполнения программы. Функции семейства printf входят в стандартную библиотеку языка C. Возможности функций семейства printf реализованы и в других языках, например Perl.
Параметрами этих функций являются форматирующая строка и переменное число параметров, которые позволяют сформировать строку. Форматирующая строка может рассматриваться как некий шаблон, описывающий структуру будущей строки и содержащий спецификации преобразования, которые сообщают функции семейства printf, где и какие данные должны располагаться и как они должны быть отформатированы. Часто спецификации преобразования называются спецификациями формата. В главе будут использоваться два этих понятия независимо друг от друга.
...
Инструментарий и ловушки
Функции семейства printf
Ниже приведен список функций семейства printf, входящих в стандартную библиотеку языка C. При неправильном использовании каждая из них может привести к ошибкам форматирующей строки.
• Функция printf() позволяет сформировать и записать отформатированную строку в стандартный поток вывода.
• Функция fprintf() позволяет сформировать и записать отформатированную строку в определяемый библиотекой libc файловый поток вывода, имя которого задается программистом.
• Функция sprintf() позволяет сформировать и записать отформатированную строку в область памяти. Неправильное использование этой функции часто приводит к переполнению буфера.
• Функция snprintf() позволяет сформировать и записать отформатированную строку заданной длины в область памяти. Является безопасной заменой функции sprintf() при защите от переполнения буфера.
В стандартную библиотеку языка C также включены функции vprintf(), vfprintf(), vsprintf() и vsnprintf(). Они выполняют те же функции, что и ранее перечисленные, но их входным параметром может быть структура varargs, описывающая переменное число аргументов.
Работа функции printf демонстрируется следующим примером:
int main()
{
int integer = 10;
printf(“this is the skeleton of the string, %i”,integer);
}
В этом примере вызывается функция printf() с двумя параметрами: форматирующей строкой и переменной, которая включается в формируемую строку вывода во время выполнения программы. Первый параметр функции – форматирующая строка, которая состоит из строки символов (статического текста) и спецификации вывода целого числа со знаком %i, соответствующей переменной integer. При вызове функции printf() значение переменной целого типа, преобразованное в символьный вид десятичного числа, будет вставлено в строку после запятой.
«this is the skeleton of the string, %i»
Ниже приведена строка, которая выводится во время выполнения программы (значение переменной равно 10).
[dma@victim server]$ ./format_examplethis is the skeleton of the string, 10
Функция printf() просматривает форматирующую строку и выводит каждый символ как он есть, буквально, пока не встретит спецификацию преобразования. Поскольку функция printf() заранее не знает, сколько параметров будет ей передано, то каждый параметр считывается из стека по мере обработки форматирующей строки в соответствии с типом каждой спецификации преобразования. В рассматриваемом примере в форматирующей строке единственная спецификация преобразования – спецификация вывода целого числа со знаком %i, обеспечивает вставку в формируемую строку переменной целого типа. Функция ожидает, что переменная, соответствующая спецификации преобразования, будет передана функции printf() вторым параметром. В архитектуре Intel (по крайней мере) параметры функций помещаются в стек до того, как будет создан стековый фрейм. Поэтому когда функция printf() считывает свои параметры из стека, они ссылаются на данные в стеке, находящиеся ниже стекового фрейма.
Читать дальше
Конец ознакомительного отрывка
Купить книгу