Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СРС_ИПОВС_МСЗИ.doc
Скачиваний:
41
Добавлен:
05.06.2015
Размер:
1.79 Mб
Скачать

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

Большинство современных атак на системные приложения основано на переполнении буфера. При этом злоумышленник пытается передать программе неадекватные данные. Как правило, при этом передается слишком много информации, которую программа по умолчанию не в состоянии переработать. Допустим, что приложение рассчитано на пере­менные с максимальным размером 10 символов, а кто-то пытается ввести переменную с 20 символами. Основная причина проблем, вызванных переполнением буфера состоит в отсутствии проверки размера данных при вводе.

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

Эксплоиты, использующие переполнение буфера, возможно, одни из самых распространенных в современной компьютерной индустрии. Эти эксплоиты используют ошибки в программах, которые не анализируют должным образом поток информации, превышающий их возможности. Попробуйте запихнуть в маленькую коробку что-нибудь большее по размеру и увидите, что от нее останется. В некоторых случаях в результате переполнения буфера программу можно заставить выполнить любую функцию, какую только придумает злоумышленник. Приложения, подверженные такой атаке, встречаются повсеместно, и атаки, приводящие к переполнению буфера, широко используются для систем UNIX, Windows NT и 2000. Разнообразные средства для этого можно без проблем найти в Internet.

Замечательную статью по этой теме, "Smashing the stack for fun and profit" (Разрушение стека ради интереса или для выгоды), написанную известным специалистом по вопросам безопасности Aleph One, можно найти в журнале Phrack, номер 7, выпуск 49. Этот электронный журнал, посвященный проблемам сетевой безопасности, находится по адресу: www.phrack.com. В нем содержится масса полезной информации для хакеров и специа­листов по защите сетей.

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

Принцип действия

Переполнение буфера основано на принципе, по которому данные хранятся в компьютерных программах. Память компьютера, или ОЗУ (RAM), — это область, где содержатся исполняемые данные или переменные, к которым обращается программа. ОЗУ— это временная память, т.е. когда система выключается, все хранящиеся в памяти данные пропадают. Оперативная память — очень быстрая среда, а потому в ней хранится информация, необходимая компьютеру при выполнения программ. Для длительного хранения используются жесткие диски или другие устройства, хранящие данные и после отключения системы, однако они более медлительны, чем ОЗУ.

Как правило, когда приложение вызывает подпрограмму, используемые в функциях переменные и указатели адресов возврата содержатся в логической структуре, известной как стек. Стек — это область памяти, в которой находятся данные для текущих нужд программы. С помощью же переменных программа принимает решения. Если в подпрограмме нужно сложить 2 числа (х и у), их значения передаются через переменные. В указателе возврата содержится адрес, куда возвращается приложение после выполнения подпрограммы. Так как операционной системе нужно вернуть управление вызывающей программе после окончания работы подпрограммы, указатель возврата показывает, к какому адресу в памяти надо возвращаться. Отведенное для хранения данных пространство памяти, или буфер, заполняется с конца, с высшего адреса до низшего, — такая архитектура буфера называется LIFO (last in, first out— последним пришел— первым обслужен). Т.е. элемент, введенный в стек последним, будет извлечен из него первым. Представьте себе обычный лифт. Когда в него заходят люди, то первым должен выйти (если все выходят на одном этаже) тот, кто последним в него вошел.

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

Аргументы функции

Аргументы функции

Рис. 1. Нормальный стек

На рис. 1 показан пример работы обычного стека памяти. Этот рисунок, как и рис. 2, взят из статьи "Smashing the stack for fun and profit".

Как видно из рисунка, адрес вызываемой функции находится на самом дне стека. Когда приложение вызывает подпрограмму, то первым делом в стек помещается адрес возврата. Не забывайте про LIFO, первый элемент, который вводится в стек (т.е. указатель возврата), изымается из него последним, как и должно быть при выполнении подпрограмм. После выполнения подпрограммы, указатель извлекается из стека, и затем управление возвращается вызываемой программе. Если бы он не использовался, то после завершения работы подпрограммы приложение не знало бы, что делать дальше. Затем переменные по мере надобности размещаются в стеке в обратном порядке, т.е. переменная 2 будет востребована перед переменной 1.

Итак, указатель (pointer) — это переменная, в которой хранится адрес памяти. Когда программа переходит на выполнение другого кода, указатель используется для запоминания его адреса. При вызове подпрограммы к ней переходит приложение, а без указателя адреса было бы непонятно, куда же возвращаться после окончания работы с подпрограммой. Таким образом, указатель хранит адрес, к которому нужно вернуться после завершения работы.

Таков принцип работы стека. Что же происходит при разрушении стека (в результате переполнения буфера)? Когда программа не проверяет и не ограничивает количество данных, копируемых в область переменной, эта область может быть переполнена. При переполнении буфера данные помещаются в область соседней переменной и, в конце концов, в указатель адреса.

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

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

Рис. 2. Разрушение стека

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