Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Skabtsov_N_V_-_Audit_bezopasnosti_informatsionnykh_sistem_-_2018.pdf
Скачиваний:
101
Добавлен:
24.01.2021
Размер:
9 Mб
Скачать

15 Переполнение буфера

Атаки, направленные на переполнение буфера

Со времен знаменитой атаки червя Морриса в 1988 году возможность переполнения буфера (buffer overflow) является основной причиной многих уязвимостей в программах и операционных системах. Зачастую теория переполнения буфера описывается достаточно сложно, с использованием специфической терминологии и приемов, непонятных многим специалистам, не задействованным в процессе разработки ПО.

В этой главе мы попытаемся сохранить баланс между простотой изложения и глубиной погружения в данный вопрос.

Введение

Информацию об эксплойтах, использующих уязвимость типа «переполнение буфера», в наши дни можно найти во всех новостных рассылках и на любых веб-сайтах, освещающих тему информационной безопасности. Так что же это такое?

Например, раздел SANS, посвященный направленным на переполнение буфера атакам, начинается со следующих слов:

Переполнение буфера может быть использовано для выполнения стороннего кода на компьютере жертвы, а поэтому оно должно относиться к уязвимостям с ВЫСОКИМ риском. Каждый месяц обнаруживается достаточно большое количество уязвимостей, связанных с переполнением буфера.

А вот как относится к этой проблеме CERT:

Несмотря на известные риски, которые были открыты уже достаточно давно, переполнение буфера на сегодняшний день остается основной причиной взломов.

Атаки, направленные на переполнение буфера    185

Хотя многие специалисты наслышаны о переполнении буфера, а также о том, что данная тема остается очень популярной и освещаемой, тем не менее в ней не такто просто разобраться. Для понимания множества примеров и описаний, которые можно найти в глобальной сети, требуются хорошие навыки программирования на языке C, знание Assembler и опыт использования отладчиков. С другой стороны, некоторые статьи описывают методику переполнения буфера, фокусируясь лишь на теоретическом, абстрактном уровне.

В данной главе мы рассмотрим несколько основных приемов переполнения буфера, стараясь, как уже было сказано выше, соблюсти баланс между простотой изложения и глубиной погружения. Придерживаясь данного подхода, мы будем описывать некоторые технические детали достаточно поверхностно, предлагая вниманию читателя упрощенную модель.

Во время описания технологий мы возьмем за основу язык программирования С, ОС Linux и архитектуру х86, широко применяемую в процессорах семейства Intel и AMD.

На самом деле все другие архитектуры и ОС также подвержены атакам, направленным на переполнение буфера, но имеют свои особенности.

Что такое переполнение буфера?

Основная цель любой программы, запущенной на компьютере, — обработка ка- ких-либо данных. Многие программы работают не со стандартным, изначально заданным набором данных, а с предоставляемой пользователем информацией. Программе необходимо хранить обрабатываемые данные в памяти компьютера, и именно с этого момента начинаются все проблемы! Многие программисты считают, что пользователь будет вводить именно ту информацию, которую ожидает программа, и никакую другую. Это предположение относится к типу данных и к их размеру, — в качестве примера можно привести строковые данные. Например, считается, что адрес веб-страницы не может быть длиннее 500 символов, поэтому для данного типа данных выделяют от 50 до 250 символов. Но некоторые программисты резервируют для такой информации область размером до 5000 символов. Этот объем зарезервированной памяти и называют буфером.

Пока что все выглядит достаточно хорошо. Теперь мы переходим к более интересной части — будет ли проверяться величина введенной пользователем информации? Доверимся ли мы безоговорочно пользователю и будем считать, что он никогда не введет больше 5000 символов, или наша программа все же будет проверять введенную строку на случай выхода за рамки выделенной памяти, если кто-то попытается ввести больше 5000 символов?

Во многих случаях эта проверка не выполняется. Это может быть связано с недостатком квалификации программиста, его ленью или другими факторами — программа просто работает с теми данными, которые предоставил пользователь.

186    Глава 15  •  Переполнение буфера

Так что же произойдет, если кто-нибудь введет 5400 символов? Первые, ожидаемые, 5000 символов будут помещены в заранее выделенную область памяти, а остальные 400 символов будут помещены в область памяти, находящуюся за рамками зарезервированного буфера, что, собственно, и является примером его переполнения.

Необходимо учитывать, что любой ввод информации пользователем должен соответствующе проверяться, иначе он может быть причиной переполнения буфера. Это включает в себя:

1)данные, вводимые в текстовые поля;

2)данные, получаемые программой сетевые данные;

3)данные из файлов;

4)данные, передающиеся как параметр из командной строки;

5)данные, получаемые от глобальных переменных (%TMP% в Windows $TMP в Linux);

6)и многие другие...

Примеры 1, 2 и 3 могут привести к удаленному переполнению буфера, тогда как остальные выполняются локально.

В зависимости от различных факторов — выбранного программистом метода резервирования памяти, а также типа внутренней организации памяти компьютера, — переполнение буфера может привести к следующим последствиям.

1.Искажение данных программы, которое может привести к неправильному результату ее работы. Например, при работе веб-сервера, в случае удачной атаки, пользователь получит не запрашиваемые данные, а ошибку 404.

2.Повреждение сегментов, контролирующих исполнение программы, может привести к ее некорректному завершению с ошибкой «access segment violation» в Linux или «general protection fault» в Windows. Появление таких ошибок указывает на то, что программа пытается получить доступ к данным, находящимся за пределами выделенной для нее области памяти.

3.Некорректное завершение работы ОС в случае, если были вовлечены структуры, контролирующие ее работу.

Конечно, это не самый лучший вариант работы ПО в случае возникновения непредвиденной ситуации, однако это намного лучше таких случаев, когда

4.Переполнение буфера дает возможность атакующему выполнить свой код на машине жертвы.

Вот почему переполнение буфера представляет собой настолько большую угрозу!

Для того чтобы понять, как происходит атака в последнем случае, далее мы рассмотрим некоторые основы устройства памяти и программ.

Атаки, направленные на переполнение буфера    187

Программы, библиотеки и бинарные файлы

Любая написанная в наши дни программа использует для обработки данных различные переменные, константы и набор всевозможных инструкций. Обычно инструкции сгруппированы в так называемые модули — или функции, если брать язык С. К счастью, многие рутинные задачи не приходится программировать отдельно, они уже доступны в виде функций в подключаемых библиотеках. Данные библиотеки, используемые для выполнения рутинных задач, могут быть получены от ОС или из других источников.

Для преобразования в машинный код инструкций, написанных, например, на языке С, используется специальная программа — компилятор. На выходе он выдает файл, содержащий инструкции, состоящие из последовательности битов, выполняемые процессором для реализации заложенной программистом задачи. При помощи отладчика можно конвертировать машинный код в код, понятный человеку, представленный с помощью языка Assembler. Другая программа, называемая линкером (linker) и во многих случаях уже включенная в компилятор, используется для интегрирования всех частей программы, например сторонних библиотек и функций, в единое целое. Файл, который получается в результате работы программиста, компилятора и линкера, называется бинарным.

Когда пользователь запускает программу, ее исполнение начинается с первой строки, что является эквивалентом первой строки написанной на языке С программы, а именно функции main(). В нетривиально написанных программах функция main() может вызывать другую функцию, которая в свою очередь может вызвать третью и т. д. Завершение программы происходит по вызову функцией main() функции exit() или тогда, когда пользователь сам прекратит ее выпол­ нение.

Угрозы

Бинарный файл исполняется в определенном контексте, который определяет уровень привилегий процесса или запускающего данную программу пользователя. Тип и описание привилегий зависят от ОС и конфигурации компьютера. Самый простой пример привилегий — это право читать и вносить исправления в содержимое файла, создавать сетевые соединения на отдельных портах, а также завершать работу программы или всего компьютера. Обычно контекст выполнения программы напрямую зависит от прав пользователя. Это значит, что программа будет иметь возможность выполнить только те действия, которые пользователь мог бы выполнить и сам, вручную. И это не зависит от заложенных программистом инструкций.

Некоторым программам необходимо для выполнения своих задач больше привилегий. Например, программа, позволяющая пользователю изменять свой пароль. Такой программе необходимо иметь возможность исправлять содержимое файла ОС, содержащего информацию о пользователях. В Unix-подобных системах для