Приоткрывая завесу
Сравнение ошибок форматирующей строки и переполнения буфера
На первый взгляд, атаки с использованием форматирующей строки и переполнения буфера очень похожи. Нетрудно увидеть, почему некоторые объединяют их в одну группу атак. Несмотря на то что они основаны на подмене адресов возврата или указателей на функции и используют при этом управляющий программный код, переполнение буфера и ошибки форматирующей строки – это совершенно разные уязвимости.
В случае переполнения буфера отказ программного обеспечения наступает при выполнении таких ответственных операций, как, например, копирование памяти при условии, что размер входных данных не соответствует размеру принимающего буфера. Переполнение буфера часто происходит при копировании строк функциями языка C. В языке C строки являются массивами переменной длины с последним нулевым байтом. Функция копирования строки strcpy() библиотеки языка C libc копирует байты из исходной строки в буфер до тех пор, пока в исходной строке не встретится нулевой байт. Если исходная строка, сформированная из входных данных программы, больше по размеру буфера, в который копируются данные, то функция strcpy() перезапишет данные смежных с буфером участков памяти. Программы переполнения буфера основаны на подмене критических данных на данные злоумышленника во время копирования строк.
Причина ошибок форматирующей строки состоит в том, что полученные извне данные включаются в форматирующую строку. Подобные ошибки можно рассматривать как сбой проверки входных данных. И по своей природе они не имеют ничего общего с ошибками определения размеров обрабатываемых данных. Злоумышленники используют ошибки форматирующей строки для записи нужных им данных в определенные области памяти. А при переполнении буфера атакующий лишен возможности выбора перезаписываемой области памяти. Другим источником путаницы является то, что использование функции sprintf() может привести как к переполнению буфера, так и к ошибкам форматирующей строки. Для того чтобы понять разницу между ними, нужно хорошо знать, что на самом деле делает функция sprintf(). Функция sprintf() позволяет программисту формировать строки с использованием стиля форматирования функции printf() и записывать их в буфер памяти. Переполнение буфера возникает тогда, когда размер сформированной строки оказывается больше размера предназначенного для нее буфера. Часто это происходит при использовании спецификации вывода строки %s, которая в формируемую строку вставляет строку переменной длины, завершающуюся нулевым байтом. Если переменная, соответствующая спецификации вывода строки %s, формируется из входных данных и ее размер не контролируется, то это может привести к переполнению буфера при записи в него отформатированной строки. Необходимо заметить, что возникшая из-за неправильного использования функции sprintf() ошибка форматирующей строки по своей сути ничем не отличается от других ошибок форматирующей строки, наступивших вследствие формирования строки из непроверенных входных данных программы.
В этой главе приведены начальные сведения об ошибках форматирующей строки, причины их возникновения и способы их использования в злонамеренных целях. Будет рассмотрена реальная уязвимость форматирующей строки и показано, как злоумышленник может ей воспользоваться.