Защита от хакеров корпоративных сетей
Шрифт:
Введение
В начале лета 2000 года специалистам в области защиты информации стало известно о новом типе уязвимости программного обеспечения. Речь идет о так называемых ошибках форматирующей строки. (Форматирующая строка – строка, используемая в операторах вывода, которая может содержать спецификации форматов и литералы.) Об ошибках форматирующей строки заговорили после 23 июня 2000 года, когда на Bugtraq была размещена программа, позволяющая атаковать FTP-демон Вашингтонского университета. При условии включения анонимного доступа к FTP, а по умолчанию в большинстве систем он включен, она позволяла удаленному злоумышленнику получить полный доступ к хостам с работающим FTP демоном Вашингтонского университета. Эта программа нанесла серьезный урон безопасности Интернет, потому что на тот момент времени FTP демон Вашингтонского университета широко использовался в сети.
У злоумышленников появилось средство удаленной компрометации десятки тысяч хостов в Интернете. Но не это повергло в шок сообщество
Непосредственная передача входных данных программы функции printf или включение их в форматирующую строку функции printf приводит к ошибкам форматирующей строки. В случае с FTP демоном Вашингтонского университета функции printf передавался аргумент команды SITE EXEC, который брался из входных данных программы демона.
О том, насколько эффективна подобная атака, говорит факт немедленного автоматического получения злоумышленником прав суперпользователя на атакованном хосте.
До появления программы атаки на FTP-демон Вашингтонского университета ошибки форматирующей строки рассматривались большинством программистов всего лишь как плохой стиль программирования, сопутствующий поспешному кодированию, и ничего более. Худшее, что происходило до этого из-за ошибок форматирующей строки, – это отказ в обслуживании. Но вскоре сообщество защиты информации изменило свое отношение к этому вопросу. Причиной компрометации многих UNIX-систем стала ошибка форматирующей строки.
Как упоминалось ранее, об уязвимости форматирующей строки стало известно в июне 2000 года. А атака на FTP-демон Вашингтонского университета была осуществлена злоумышленником, известным как tf8, 15 октября 1999 года. Если предположить что после этого преступникам стало известно, как ошибки форматирующей строки могут использоваться для проведения атак, то у них было более восьми месяцев для поиска и использования подобных ошибок в других программах. Эта догадка основана на предположении о том, что во время атаки на FTP-демон Вашингтонского университета впервые были использованы ошибки форматирующей строки. Хотя нет особых причин в это верить, поскольку комментарии в программе взлома не свидетельствуют о том, что их автор открыл какой-то новый способ атаки.
Вскоре после того, как стало известно о существовании ошибок форматирующей строки, появилась информация об уязвимости ряда программ атакам этого типа. В настоящий момент известны десятки программ атаки, использующих ошибки форматирующей строки.
Что касается официальной классификации, ошибки форматирующей строки на самом деле нельзя выделить в отдельную категорию ошибок программного обеспечения, как, например, ошибка «состояние гонок» (race conditions) при конкуренции программ за ресурсы или переполнение буфера. Скорее, ошибки форматирующей строки относятся к категории ошибок проверки входных данных (input validation bugs). Основная причина их появления состоит в том, что программисты включают в форматирующую строку входные непроверенные данные программ.
Приоткрывая завесу
Сравнение ошибок форматирующей строки и переполнения буфера
На первый взгляд, атаки с использованием форматирующей строки и переполнения буфера очень похожи. Нетрудно увидеть, почему некоторые объединяют их в одну группу атак. Несмотря на то что они основаны на подмене адресов возврата или указателей на функции и используют при этом управляющий программный код, переполнение буфера и ошибки форматирующей строки – это совершенно разные уязвимости.
В случае переполнения буфера отказ программного обеспечения наступает при выполнении таких ответственных операций, как, например, копирование памяти при условии, что размер входных данных не соответствует размеру принимающего буфера. Переполнение буфера часто происходит при копировании строк функциями языка C. В языке C строки являются массивами переменной длины с последним нулевым байтом. Функция копирования строки strcpy библиотеки языка C libc копирует байты из исходной строки в буфер до тех пор, пока в исходной строке не встретится нулевой байт. Если исходная строка, сформированная из входных данных программы, больше по размеру буфера, в который копируются данные, то функция strcpy перезапишет данные смежных с буфером участков памяти. Программы переполнения буфера основаны на подмене критических данных на данные злоумышленника во время копирования строк.
Причина ошибок форматирующей строки состоит в том, что полученные извне данные включаются в форматирующую строку. Подобные ошибки можно рассматривать как сбой проверки входных данных. И по своей природе они не имеют ничего общего с ошибками определения размеров обрабатываемых данных. Злоумышленники используют ошибки форматирующей строки для записи нужных им данных в определенные области памяти. А при переполнении буфера атакующий лишен возможности выбора перезаписываемой области памяти. Другим источником путаницы является то, что использование
В этой главе приведены начальные сведения об ошибках форматирующей строки, причины их возникновения и способы их использования в злонамеренных целях. Будет рассмотрена реальная уязвимость форматирующей строки и показано, как злоумышленник может ей воспользоваться.
Уязвимость форматирующей строки
Для понимания сути уязвимости форматирующей строки необходимо иметь четкие представления о работе функции 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 значение переменной целого типа, преобразованное в символьный вид десятичного числа, будет вставлено в строку после запятой.