Новость из категории: Информация » IT

Ошибки сегментации и безопасность: «канарейки» в glibc и NX-бит

Содержание:
1. Модель памяти процесса и атаки на переполнение буфера, стек;
2. Куча;
3. Средства защиты, способы их обхода и слова-канарейки;
4. «Канарейки» в glibc и NX-бит (Вы читаете данный раздел);
5. Коммерческая сторона и конкуренты;
«Канарейки» в glibc

Ошибки сегментации и безопасность: «канарейки» в glibc и NX-бит

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

Такие альтернативы имеют суффикс «_chk» - printf_chk(), scanf_chk() и так далее. У программистов нет нужды обращаться к этим функциям напрямую - их вызов подставляется компилятором в код программы автоматически вместо обычных функций, если определена константа _FORTIFY_SOURCE и только если включена оптимизация. При срабатывании этих «канареек», мы получим схожее сообщение о переполнении буфера («*** buffer overflow detected ***»), а заодно и трассировку вызова функций и карту памяти процесса (фактически содержимое уже упоминавшегося файла /proc//maps).

Более того, при определении константы _FORTIFY_SOURCE некоторые ошибки можно «отловить» еще на этапе компиляции - если компилятор определит, что переполнение будет возникать в любом случае (например, вы пытаетесь записать строку из трех символов в массив из двух байтов), он выдаст соответствующее предупреждение.

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

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

NX-бит

Этот способ заключается в использовании NX-бита (No eXecutable bit) для страниц памяти процесса, не содержащих код. Этот подход не предполагает непосредственного обнаружения факта переполнения; вместо этого он пытается затруднить использование подобных ошибок для исполнения вредоносного кода.

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

На заре развития информационных технологий можно было перезаписывать инструкции прямо в коде программы. Но, как быстро показала практика, возможность перезаписывать код программы в процессе ее исполнения может преподнести немало сюрпризов даже без участия злоумышленников. Поэтому во всех современных системах области памяти, содержащие исполняемый код, помечаются как «read-only» («только для чтения») на аппаратном уровне сразу после того, как код загружается в память. В ходе работы программы модификация этих областей памяти невозможна.

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

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

Реализация NX-бита в аппаратуре и добавление его поддержки в операционные системы стало серьезным шагом в укреплении безопасности и наверняка позволило пресечь множество атак. Однако, как это нередко бывает, потребовалось совсем немного времени для создания элегантного способа обхода этой защиты.

Основной целью NX-бита является предотвращение запуска каких-либо инструкций из области данных, и с этой задачей он блестяще справляется. Однако так ли необходима возможность запуска кода из области данных для успешной атаки? Оказывается, что совсем нет. Ведь подавляющее большинство приложений в Linux динамически скомпонованы с библиотекой libo, в которой есть такие замечательные функции, как system() и семейство exec(), позволяющие выполнить любую команду оболочки или запустить произвольную программу.


Кстати, если Вы хотите полностью обезопасить личные данный пользователей, пользующихся вашим онлайн сервисом? Тогда аутсорсинговые услуги (http://itcloud.pro/outsorsing), предоставляемые настоящими профессионалами своего дела, - это именно то, что Вам нужно! Узнайте подробности прямо сейчас на itcloud.pro.

Так что вообще-то нет нужды создавать свои собственные функции, помещать их в область данных, а потом передавать им управление - достаточно передать управление одной из упомянутых функций libo, передав ей нужные параметры - например, вызвав system(«/bin/bash»). Этому NX-бит не мешает - ведь функция system() находится в области кода, и ее запуск легитимен. Атака, обходящая NX-бит посредством вызова функций библиотеки libo, получила название «Return-Into-LibC».

Конечно, остаются задачи определения адреса нужной функции в области памяти процесса и формирования нужных аргументов, но они не является неразрешимыми. Существуют специальные приемы, дополнительно усложняющие эти задачи, такие как технология рандомизации адресного пространства процесса (Address Space Layout Randomization), при использовании которой библиотеки при каждом старте программы располагаются в ее адресном пространстве случайным образом. Из-за этого нельзя заранее узнать адрес той или иной библиотечной функции, и атакующему приходится определять адрес нужной функции непосредственно в ходе работы программы. Впрочем, это хоть и сложно, но выполнимо. К тому же для успешной атаки не обязательно использовать каждое переполнение буфера, достаточно одного удачного «попадания». Так что NX-бит работает, но при большом желании обходится.

Итак, для предотвращения атак на переполнение буфера есть достаточно мощные универсальные средства, защищающие от атак все приложения системы. Однако, несмотря на высокую эффективность, стопроцентную гарантию защиты они дать не могут. Существующие технологии затрудняют атаки, но отнюдь не делают их невозможными; подобные средства могут остановить «юных хакеров», но вряд ли станут серьезным препятствием для профессионалов.

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

Рейтинг статьи

Оценка
0/5
голосов: 0
Ваша оценка статье по пятибальной шкале:
 
 
   

Поделиться

Похожие новости

Комментарии

^ Наверх