» ГЛАВНАЯ > К содержанию номера
 » Все публикации автора

Журнал научных публикаций
«Наука через призму времени»

Август, 2017 / Международный научный журнал
«Наука через призму времени» №5 2017

Автор: Рычков Вячеслав Андреевич, студент
Рубрика: Технические науки
Название статьи: Защита от переполнения буфера

Статья просмотрена: 944 раз

ЗАЩИТА ОТ ПЕРЕПОЛНЕНИЯ БУФЕРА

Рычков Вячеслав Андреевич

Студент группы С8201, специальность: «Компьютерная безопасность»

Дальневосточный Федеральный Университет

 

Аннотация. Данная статья посвящена рассмотрению проблемы переполнения буфера в современных компьютерах: самые распространенные виды атак и методы защиты. Здесь представлены методы, которые позволят избежать переполнения буфера при написании программ на языке программирования С++.

Ключевые слова: буфер, стек, переполнение буфера.

 

Актуальность

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

Предисловие

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

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

Основные виды атак, связанные с переполнением буфера

а) Атака на стек.

Стеки - это структуры переменной длины, предназначенные для хранения объектов. При переполнении буфера и атаке на стек злоумышленник добавляет в стек лишние данные, тем самым перезаписывая данные, которые, уже в нем хранятся. Нельзя не заметить, что это приведет к повреждениям данных в программе. Лишние данные приводят к тому, что программа начинает выполнять произвольный код. Происходит это в связи с тем, что переполненный буфер перезаписывает адреса возврата, которые хранятся в стеке. Адреса возврата передают на процессор те функции, которые следует выполнять следующими после завершения текущей функции. И если это значение будет перезаписано, то неизвестно, что процессор будет выполнять дальше. Злоумышленник, взяв контроль над переполнением буфера, сможет контролировать и адреса возврата. Таким образом злоумышленник получает контроль над последовательностью действий процессора, а следовательно, и над программой.

б) Атаки на функции форматирования строк

Данные атаки тоже влияют на стек, но изменения при этом гораздо меньше, чем при переполнении буфера в стеке. Злоумышленник модифицирует пути исполнения программы, используя функции форматирования символьных переменных. Применив данные пользователей как аргументы функций форматирования строк (например, printf, syslog, setproctitle и другие), злоумышленник сможет получить доступ к управлению программой, передав приложению строку с символами форматирования (%n, %f, %p и т.д.). Выполнив вышеизложенное, он сможет:

1. выполнять на сервере произвольный код

2. вмешиваться в работу программы и вызывать в ней ошибки

3.получать значения из стека

в) Атаки на heap (кучи)

Heap -  память, которая постоянно используется на всем протяжении выполнения программы (а не временно, в отличии от стека). При атаке на heap стек не затрагивается. Принцип атаки такой, как и при атаке на стек. Исключение лишь в том, что вредоносные изменения вносятся не в стек, а в heap.

Способы защиты от переполнения буфера

а) Корректировка кода программы для устранения уязвимостей.

Чаще всего переполнение буфера происходит по причине того, что в программе не предусмотрены проверки выхода за границу буфера. Отдельное место в этом вопросе занимает язык С++. Он не содержит средств контроля соответствия типов, в связи с чем в переменные одного типа можно занести значения других типов. Также в С++ используются функции (sprint, strcpy), которые не проверяют длину переменных, что также приводит к переполнению.

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

1. замена уязвимых функций sprint, strcpy на аналогичные функции, которые проверяют длину строки, - snprint, strncpy.

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

б) Использование неисполнимого буфера

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

в) Проверка выхода за границы

При данном методе при каждом обращении к переменной происходит проверка ее длины (превышения допустимых границ). Настоящий метод реализован в ряде компиляторов (Compaq C, Alpha Linux). Известно дополнение для gcc, в котором реализована проверка выхода за границы. Данный метод нейтрализует все атаки, которые связаны с переполнением буфера, так как при его использовании переполнение невозможно. Но у него есть существенный минус - снижение производительности программы в несколько раз.

г) Использование различных защитных утилит, таких как PointGuard, StackGuard, StackShield и др.

Ошибки пользователей С++, приводящие к переполнению буфера, и методы их устранения

а) Использование функций, не проверяющих длину данных

Наиболее часто переполнение буфера возникает в тех программах, где используются функции, не проверяющие длину входных и выходных данных. Например, это функции strcat, gets и другие. Рассмотрим работу таких функций на примере.

char result[100]; int i=0;

 ZeroMemory(result,100);

 i=recv(s,buff, result (buff));

 do

            {

                        strcat(result,buff);

            }

while (i!=0);

В указанном коде происходит вот что. Информация передается с сокета s в buff. Ее размер равен sizeof(buff). Но в дальнейшем в цикле будет происходить следующее: массив buff прибавится к массиву result, и проверка длины выполнена не будет. И если сервер получит информацию, размер которой более 100 байт, то произойдет переполнение. Таких ситуаций можно избежать, если задать условие, которое будет проверять длину входных данных. На данном примере это может выглядеть так:

If(lstrlen(buff)+lstrlen(result)<sizeof(result)strcat(result,buff);
б) Ошибка при явном преобразовании

В отдельных ситуациях не происходит явного преобразования данных. Например, к переменной типа int приравниваются результаты вычислений типа float, double и т.д. В такой ситуации переполнение будет незначительным (несколько байт), но все зависит от того, в каком месте расположены эти переменные, и какие расположены рядом. Через подобную уязвимость можно передать указатель на шеллкод.

в) Ошибка на единицу

Нередко люди, использовавшие ранее другие языки программирования, а в настоящее время работающие на языке С++, допускают так называемую "ошибку на единицу". Ее суть в том, что в С++ нумерация массива по умолчанию начинается с 0. Об этом программист может забыть, что в результате может привести к переполнению буфера. Решение данной проблемы весьма простое - нужно подобрать правильный знак между массивами (равно, больше, меньше).
            Вывод

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

К основным видам атак, связанным с переполнением буфера, относятся атаки на стек, атаки на функции форматирования строк, атаки на heap.

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

К основным ошибкам пользователя C++, способствующим переполнению буфера, относятся использование функций, не проверяющих длину переменных, ошибки при преобразовании данных, «ошибка на единицу».

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

 



Список литературы:

  1. Лекции по информационной безопасности. http://megalektsii.ru/s47090t1.html
  2. Питер Брайт. Как устроены дыры в безопасности: переполнение буфера.https://habrahabr.ru/post/266591/
  3. Атака на функции переполнения строк. http://dammlab.com/bezopasnost-pk/ataka-na-funkcii-formatirovaniya-strok-format-string-attack.html
  4. Защита от переполнения. Часть 1.https://hpc.name/text/get/786/p1.html


Комментарии:

Фамилия Имя Отчество:
Комментарий: