Переполнение буфера на системах с неисполняемым стеком

       

Несмотря на все усилия, вырытые


Несмотря на все усилия, вырытые рвы и воздвигнутые защитные сооружения, интенсивность удаленных атак не снижается и отражать их становится все труднее. Хакеры научились маскировать вредоносные процессы под LINUX/BSD и NT, разобрались с брандмауэрами и освоились с распределенными системами — сотни тысяч зараженных машин, управляемых через IRC — это настоящая армия, разрушительная как монгольская орда. Интересы отдельных пользователей, пострадавших от атаки, отходят на задний план, уступая место вопросам безопасности всей инфраструктуры в целом. А инфраструктура — это уже серьезно.
Анализ показывает, что подавляющее большинство атак используют ошибки переполнения (buffer overflow), фундаментальную природу которых мы уже обсуждали (см. "ошибки переполнения буфера извне и изнутри как обобщенный опыт реальных атак"). Львиная доля таких ошибок находится в Internet Explorer'e, что в частности и явилось причиной перехода NASA на FireFox (http://www.securitylab.ru/news/242844.php?R1=RSS&R2=allnews), что можно только приветствовать, однако, FireFox (как и все остальные браузеры) не свободен от ошибок и в нем присутствует большое количество критических уязвимостей, позволяющих злоумышленнику выполнить свой код (далее по тексту называемый shell-кодом). Вот только одна из таких дыр: http://www.securitylab.ru/vulnerability/240254.php.

Рисунок 1 схематичное изображение стека. стрелка показывает направление в котором растет стек. локальный буфер "растет" в противоположном направлении и при определенных обстоятельствах может затирать адрес возврата
Никакое программное обеспечение небезопасно! Даже если своевременно устанавливать свежие заплатки всегда существует риск, что хакер найдет новую дыру о которой еще никто не знает и с успехом воспользуется ею. Кстати говоря, разработка атакующих программ за последние несколько лет поднялась с колен чистого энтузиазма и встала на коммерческих поток с большими вложениями. Стоимость гарантированно работающего эксплоита зачастую доходит до $2.000.
Можно только догадываться кому и зачем это нужно…
В очередной раз возникло понимание, что "дальше так жить нельзя" (c) и нужно что-то решать. Попытки покончить с удаленными атаки неоднократно предпринимались еще с 80'х годов, особенно после Червя Морриса, но все безуспешно. Как говорят в этих случаях американцы: серебренной пули нет! Оборотня не убить! Тем не менее, Microsoft решилась отчаянный шаг и возродила старые идеи, отрытые на помойке истории и реализованные без учета понимания ситуации наших дней.
Технология DEP (Data Execution Protection — Защита от Выполнения Данных), реализованная в Windows XP SP2 и Server 2003 SP1, делает секцию данных, стек и кучу неисполняемыми, что (теоретически) предотвращает засылку shell-кода и отсекает целый класс удаленных атак, основанных на переполнении.
В чем же революционность такого решения? Ведь еще со времен Windows 95 (не говоря уже про стандарт POSIX, принятый в 1985 году) x-атрибут (от eXecutable – исполняемый) имеется только у кодовой секции и отсутствует у всех остальных. Достаточно взять любой ELF/PE-файл и посмотреть! Так-то оно так, но… у x86 процессоров на этот счет имеется свое собственное мнение: на уровне страниц процессор поддерживает всего лишь два атрибута защиты: -a- (от accessed – страница доступна для чтения/исполнения) и -w- (от write – запись разрешена). Никакого x-атрибута в PTE нет и он присутствует только в таблице селекторов, а это значит, что мы не можем выборочно разрешать/запрещать исполнение кода для отдельных страниц, а только для всего сегмента целиком. Вот потому, Windows с ее плоской моделью памяти, вынуждена трактовать атрибут -r- как -x-, а -x- как -r-. То есть, право на чтение страницы дает неявное право на ее исполнение и наоборот.
На самом деле, никакого произвола со стороны процессора здесь нет: проблему можно решить и в рамках плоской модели. Достаточно "всего лишь" перегруппировав сегменты и установить правильные лимиты (см. рис. 2).




Естественно, это требует больших телодвижений со стороны разработчиков ядра (необходимо использовать раздельные ITLB/DTLB и т. д.), что их совсем не вдохновят.

Рисунок 2 "эмуляция" NX/XD битов на x86 процессорах
Почему же в x86 не была предусмотрена возможность задания x-атрибута на уровне страниц? Риторический вопрос… Скорее всего, во времена проектирования 80386 это было никому не нужно, вот и решили не усложнять логику процессора без необходимости. А вот в Itanium'е этот атрибут присутствует изначально и специальный бит, известный под аббревиатурой XD (от eXecute Disable – выполнение запрещено), определяет: разрешено ли выполнение кода в данной странице или нет.
Аналогичный бит имеется и в процессорах AMD-64 (Opteron и Athlon-64), только там он называется NX (от No-eXecute — не выполняемый). Кому-то в компании пришла в голову "здравая" мысль объявить x-атрибут "технологией" и вокруг NX-бита тут же развернулась рекламно-маркетинговая акция "Enhanced Virus Protection" (Расширенная Вирусная Защита) или сокращенно EVP. На стайте компании выложено множество красочных роликов, демонстрирующих как AMD борется с вирусами на уровне процессора (!). Неудивительно, что 64-битная редакция NT от рождения имеет неисполняемую кучу и стек! Microsoft просто подхватила брошенный ей атрибут защиты и встроила его в систему, чтобы лишний раз продемонстрировать, что она не отстает от прогресса. В этом-то и заключается сущность аппаратного (hardware-enforced) DEP.

Рисунок 3 организация виртуальной памяти

Рисунок 4 NX бит — новый атрибут защиты в PDE/PTE
Воспользовавшись шумихой, развернутой AMD, компания Intel внедрила поддержку XD-бита в 32-разрядные Pentium'ы, сделав эту "технологию" доступной всем и каждому (желающих пересесть на AMD-64 ради одно лишь DEP'а набралось не так уж и много). Строго говоря, Nx присутствует не только в "настоящих" 64-битных


процессорах от AMD, но и в собранных на 64-битном ядре 32-битных (т. е. работающих в состоянии перманентной эмуляции i386) процессорах – например Sempron (около 99 долларов за штуку)
. Достаточно лишь воткнуть последний Pentium-4 и обновить ядро, чтобы Windows могла задействовать новые аппаратные возможности, и тогда при попытке выполнения прикладного кода в куче, секции данных или на стеке возбуждается исключение типа STATUS_ACCESS_VIOLATION (C0000005h) и, если только программист не установил свой обработчик SEH, выполнение программы аварийно завершается с выдачей сообщения "to help protect your computer, Windows has closed this program" (см. рис. 5).

Рисунок 5 реакция DEP на попытку выполнения кода на стеке
В режиме ядра при попытке выполнения кода в неисполняемой области памяти возбуждается исключение ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY c BugCheck-кодом FCh, обрушивающим систему в "синий экран". 64-битные версии NT защищают от исполнения стек ядра, paged и session pool, а 32-битные — только стек.

Рисунок 6 регионы памяти, защищенные от выполнения кода
Если процессор не поддерживает NX/XD-битов, система активирует программный (software-enforced) DEP, который даже и не пытается эмулировать неисполняемый стек/кучу (а ведь мог бы!). Технология, которую продвигает Microsoft, в действительности представляет собой примитивную защиту обработчика структурных исключений, ранее известную под именем SafeSEH. Она никак не препятствует выполнению shell-кода, но затрудняет использование структурных исключений shell-кодом, если тот вдруг решит их использовать. Подробнее об этом можно прочитать в статье "SEH на службе контрреволюции", электронная копия которой лежит на сервере ftp://nezumi.org.ru.
Мы будем обсуждать только аппаратный DEP, поскольку его сложнее всего обойти. Некоторые даже считают, что это вообще невозможно: "…на сегодняшний день не существует ни одного хотя бы концептуального эксплойта, на практике доказывающего возможность поражения Windows XP с установленным пакетом обновления Service Pack 2" (www.computerra.ru/softerra/36652).Если бы DEP проектировался головой, все так бы и было. Однако, Microsoft идет своим особым путем, который умом не понять, и DEP обходится без труда, а вот у легальных пользователей возникают множество проблемы, о которых мы еще поговорим.
Неправильно называть DEP защитным механизмов. До "защитного механизма" ему так же далеко как одиноко торчащему рулю до самосвала. DEP – это всего лишь поддержка атрибутов защиты страниц и ничего более!

Содержание раздела