Автор: (c)Крис Касперски ака мыщъх
Атаки на кучу (она же динамическая память) приобретают все большую популярность, но методы переполнения, описанные в доступных хакерских руководствах, по ходу дела оказываются совершенно неработоспособными. Рассчитанные на древние системы, они не в курсе, что в новых версиях все изменилось. Более того - Free-, Net- и OpenBSD используют различные стратегии защиты кучи, особенности строения которой необходимо учитывать при написании exploit'ов. Мыщъх проделал титаническую работу, исследовав все версии всех BSD-систем, и теперь не успокоится, пока не поделится добытой информацией с читателями.
Сезон переполняющихся куч начался со статьи "Once upon a free()", опубликованной анонимусом в 39h номере phrack'а (8 января 2001 года) со ссылкой на более раннюю работу известного хакера Solar'а Designer'а (датируемую 25 июлем 2000 года), в которой тот описал механизм передачи управления на shell-код, использующий особенности реализации макроса unlink в библиотеке glibc-2.2.3, поставляемой вместе с Linux. До этого хакерам было известно лишь стековое переполнение с подменой адреса возврата из функции. Переполнение кучи в общем случае приводило лишь к бездумному разрушению служебных структур динамической памяти и краху уязвимого приложения. Новый класс атак открывал нехилые перспективы непаханой целины и обозначенная статья приобрела огромную популярность, породив кучу перепечаток в различных туториалах и емагах.
В конце июля 2002 года на сеть обрушился червь Slapper, поражающий Linux-боксы и распространяющийся путем переполнения кучи через ошибку переполнения стека в OpenSSL, что представляло собой весьма нетривиальную задачу.
Для BSD-систем такой механизм оказался неприменим в силу существенных конструктивных отличий строения кучи, но уже 14 мая 2003 года хакер по кличке BBP обосновал, как атаковать аллокатор, разработанный программистом по имени Poul Henning Kamp (далее по тексту phk-аллокатор). В то время phk-аллокатор использовался в Free-, Net- и OpenBSD в качестве основного аллокатора, выбираемого по умолчанию, теперь же он остался только в Net- и OpenBSD (причем, в OpenBSD - в сильно переработанном виде), в результате чего старые трюки перестали работать и молодые хакеры, обкурившиеся чужих статей, никакого кайфа не словили, а высели на полный облом, завалив мыщъх'а грудами писем - почему это не работает, как теперь жить и что делать? Примечание: аллокатором (от англ. "to allocate" - размещать, выделять), называется совокупность механизмов, ответственная за распределение памяти и реализующая операции выделения, освобождения и (опционально) изменения размеров ранее выделенных блоков. Существует три типа аллокаторов: автоматические - работающие со стеком; статические - работающие с секцией данных и динамические - работающие с кучей. Если явно не оговорено обратное, то под аллокатором подразумевается именно динамический аллокатор.
Вердикт: курить, конечно, полезно, но реальный приход дают только свои собственные исследования, особенно в наш бурный век, когда опубликованные методы атаки теряют актуальность в течении нескольких месяцев. Так вот, насчет исследований...
В конце 2005 года хакер по кличке Phantasmal Phantasmagoria написал статью "The Malloc Maleficarum Glibc Malloc Exploitation Techniques", предлагающую новые механизмы атаки, пробивающие glibc версии 2.3.5 и выше. Статья остается актуальной и по сей день, пусть и не без коррекции с учетом рандомизации адресного пространства, сторожевых страниц и других новомодных защитных технологий, появившихся в начале 2006 года.
В середине 2006 года хакер по кличке Ben Hawkes выступил на конференции RexCon с презентацией "Exploiting OpenBSD", в которой он показал, как атаковать кучу самой защищенной операционной системы всех времен и народов. Разработчики OpenBSD довольно оперативно отреагировали на ситуацию, выпустив обновленную версию аллокатора, затыкающую часть дыр. Разработчики Free- и NetBSD чешутся до сих пор, так что для хакерства складывается весьма благоприятная ситуация.
Мыщъх не предлагает готовых рецептов, но зато указывает на направление, двигаясь в котором можно поломать не только текущие, но и последующие версии аллокаторов во Free-, Net- и OpenBSD-системах, включая Linux и ненавистную всем Висту с новоявленным Longhorn'ом (он же Server 2008).
Рисунок 1. Схематичное строение кучи в BSD-системах.
Прежде, чем углубляться в омут технических подробностей (в который легко занырнуть, но не каждому удается вынырнуть наружу), совершим беглый экскурс по новейшим аллокаторам, обозначив ключевые технологии и ответив на вопрос, почему существующие exploit'ы перестали работать.
Рисунок 2. Рандомизация адресного пространства в OpenBSD.
Главная сложность атаки на кучу заключается в огромном количестве версий аллокаторов, каждая из которых требует индивидуального подхода, поэтому представляет большой интерес проследить этапы развития аллокаторов во Free-, Net- и OpenBSD системах. Полный перечень изменений занял бы пару десятков страниц и был бы таким же скучным и труднопроходимым, как и "Капитал" Маркса (часто используемый в качестве снотворного).
К счастью, ничего подобного делать не требуется, поскольку эта информация уже представлена в удобочитаемом виде на сайтах разработчиков. Web-CVS рулит, когда требуется изучить хронологию эволюции отдельного файла - в данном случае malloc.c, доступном по следующим адресам:
Мы же сосредоточимся только на "судьбоносных" изменениях, связанных с введением в строй новых защитных механизмов, а модернизацию служебных структур динамической памяти оставим за бортом.
Ранние версии FreeBSD использовали простой и тормозной аллокатор, написанный в 1982 году программистом по имени Chris Kingsley (kingsley@cit-20) и условно именуемый Caltech-аллокатором.
В сентябре 1995 года Caltech-аллокатор был заменен намного более продвинутым аллокатором, написанный программистом Poul-Henning Kamp <phk@FreeBSD.ORG> (phkmalloc-аллокатор или, для краткости, "phk"), который и стал основным аллокатором для xBSD систем на последующую пару десятков лет. Выпущенный под лицензией "THE BEER-WARE LICENSE" (бесплатно как пиво) он находит себе применение и по сей день...
Начиная с октября 1995 года, в phk-аллокаторе появились "zero" и "junk" опции, позволяющие диагностировать некоторые виды переполнения кучи, впрочем в то время кучу в BSD системах переполнять еще никто не собирался и потому эти улучшения остались незамеченными.
Декабрь 1995 года ознаменовал череду радиальных изменений, направленных главным образом на усиление производительности и повышение эффективности использования памяти. Побочный эффект - изменение служебных структур кучи - уничтожил все существующие exploit'ы, однако по официальным данным ни одного работающего exploit'а, атакующего кучу, на тот момент еще не существовало.
Затем последовала череда многочисленных мелких изменений, за которой незаметно прошел 2001 год, отмеченный появлением exploit'ов под Linux; 2003 год, открывший эру атак на кучу xBSD; закончился 2005 год, к концу которого хакеры справились с новыми версиями glibc, а разработчики FreeBSD все никак не реагировали на ситуацию и от атак не защищались, перекладывая эту заботу на плечи компилятора (учитывая, что большинство программ использует кучу не напрямую, а работает через glibc, позицию создателей FreeBSD можно понять).
Наконец, в январе 2006 года древний phk-аллокатор был отправлен на свалку истории, а на его место пришел новый, улучшенный jasone-аллокатор, созданный программистом по имени Jason Evans. Функции malloc(), calloc(), posix_memalign(), realloc() и free() были полностью переписаны с учетом требований защиты и масштабируемости. Ну, масштабируемость нас никак не волнует, так что сразу перейдем к защите: в jasone-аллокаторе появились сторожевые "красные зоны" (redzones), располагающиеся до и после всех блоков памяти, а также проверки на переполнения буферов, существенно затрудняющие атаку, но...
...в марте 2006 года "красные зоны" были удалены по соображениям производительности, а в CVS-дереве появился следующий комментарий: "Remove redzones, since program buffer overruns are no longer as likely to corrupt malloc data structures" - "удалены красные зоны, поскольку переполнение буферов ничуть не более вероятно, чем разрушение внутренних структур динамической памяти", из чего надо полагать, что ни буфера, ни внутренние структуры не были защищены. Правда, в силу своей новизны jasone-аллокатор оказался достаточно стойким и exploit'ы, ориентированные на phk-аллокатор, с ним обломались, но(!) базовые принципы атаки не изменились и требовалась всего лишь адаптация exploit'ов под новые структуры данных.
На момент написания этих строк (конец 2007 года) FreeBSD продолжает использовать незащищенный jasone-аллокатор, представляющий собой легкую мишень для атаки.
Рисунок 3. malloc.c на CVS-дереве FreeBSD.
Операционная система NetBSD, "отбранченная" от FreeBSD, во многом повторила ее путь. Сначала в ней использовался Caltech-аллокатор, но в июне 1999 года он был заменен phk-аллокатором, позаимствованном из FreeBSD и портированным на все платформы, которые только поддерживает NetBSD. Изменения внутренних структур данных динамической памяти оказались несущественными и потому обе системы оказались "совместимыми" с точки зрения exploit'ов.
Очередная серия изменений произошла в мае 2001 года, когда работники NetBSD вновь позаимствовали новую версию phk-аллокатора из FreeBSD, слегка адаптировав ее в соответствии со своей философией и добавив ряд мелких проверок на переполнение кучи, которые, в общем-то, оказались совершенно несущественными с хакерской точки зрения.
В настоящий момент NetBSD продолжает использовать незащищенный phk-аллокатор. Рандомизация адресного пространства реализована только в стеке и секциях кода/данных, но куча остается нерандомизованной. Сторожевые страницы также отсутствуют, как отсутствует обфускация указателей, а потому NetBSD легко атакуется древними exploit'ами. Впрочем, чтобы захватить управление, хакеру необходимо преодолеть защитный механизм PaX, интегрированный в NetBSD, подробнее о котором можно прочитать в моей статье "Переполнение буфера на системах с неисполняемым стеком" (см. http://nezumi.org.ru/zq-nx.uncensored.zip), но это по любому тема совсем другого разговора, не имеющего к куче никакого отношения.
Рисунок 4. malloc.c на CVS-дереве NetBSD.
Ох уж эта драконическая OpenBSD!!! Самая трудная мишень для атаки! Можно даже сказать, практически неприступная, но именно эта неприступность и возбуждает хакеров, заставляя их искать весьма нетривиальные пути. Чтобы развеять мир о неприступности OpenBSD достаточно вспомнить Ben'a Hawkes'а, атаковавшего кучу OpenBSD в 2006 году, то есть, когда в ней уже были реализованы основные защитные механизмы, отсутствующие у конкурентов, но не будем забегать вперед и вернемся назад в далекий 1995 год, когда в OpenBSD использовался Caltech-аллокатор со всеми дырами, что в нем были.
В августе 1996 года разработчики OpenBSD позаимствовали phk-аллокатор из FreeBSD без каких бы то ни было существенных переделок, что позволило хакерам атаковать OpenBSD с той же легкостью, что и остальные системы.
В октябре 2003 года (то есть, спустя полгода после открытия сезона атак на кучу, начатую хакером BBP), коллектив OpenBSD оказался первым, кто отреагировал на эту угрозу и выпустил усиленную версию phk-аллокатора, добавив в него сторожевые страницы и рандомизацию кучи, что вызвало бурю восторга среди "трудящихся", которые вовсю использовали новый аллокатор на продакшен машинах, считая себя абсолютно неуязвимыми.
Коллектив же OpenBSD тем временем вместо того, чтобы почивать на лаврах, не отходил от станков, тьфу, от клавиатур, и ковал новое секретное оружие, представленное народу в августе 2004 года. Появилась обфускация указателей, а рандомизация кучи была существенно усилена и теперь она затрагивала не только адреса блоков памяти, но и местоположение служебных структур, что делало кучу полностью непредсказуемой и очень-очень сложно атакуемой, однако в июне 2005 года по многочисленным просьбам "трудящихся" обфускация указателей была отправлена в отставку, поскольку оказалась чересчур тяжеловесной и негативно влияющей на производительность.
"Наш ответ Чемберлену" - вот девиз аллокатора, выпущенного в 2006 году и устраняющего ряд слабостей реализации, продемонстрированных на презентации "Exploiting OpenBSD". Говоря техническим языков, для структур pginfo и pgfree был создан специальный аллокатор, размещающих их в отдельной области памяти (прежние версии аллокатора использовали для этих целей функцию imalloc), чанки (chunks) переместились в специальный массив, размещаемый в случайном месте адресного пространства, в результате чего затереть служебные данные кучи в последних версиях OpenBSD практически невозможно, но создать подложный чанк и "скормить" его функции free() - это без проблем, ведь обфускация указателей по умолчанию отключена! Однако найти уязвимый указатель, пригодный для затирания, удается далеко не всегда, так что OpenBSD не без ложной скромности носит звание самой защищенной операционной системы (только не надо путать "самую защищенную" с "защищенную вообще").
Рисунок 5. malloc.c на CVS-дереве OpenBSD.
Вот мы и пробежались галопом по всем аллокаторам, которые только есть, рассмотрев их сильные и слабые стороны. И что же мы обнаружили в итоге? FreeBSD атаковать ничуть не сложнее чем NetBSD, однако из-за различных типов применяемых в них алокаторав exploit'ы получаются несовместимыми. OpenBSD - единственная система, существенно затрудняющая атаки на кучу, но... вовсе не делающая их принципиально невозможными!