Обзор эксплойтовКрис Касперски Хакер, номер #113, стр. 113-048-1 После потока интересных дыр неожиданно наступило затишье. За последнее время не обнаружено ни одной значительной уязвимости, которую можно использовать для массированных хакерских атак. Поэтому приходится довольствоваться дичью поменьше, благо, таковая имеется, а заплатки – отсутствуют. Как следствие, в Сети находится куча беззащитных рабочих станций и серверов.Microsoft Windows – ошибка DNS-клиентаBriefMicrosoft продолжает радовать нас новыми и старыми дырами, переходящими из одной версии Windows в другую. Первые атаки на DNS протокол были зафиксированы в далеком 1989 году и сводились к генерации подложного DNS ответа, который, тем не менее, воспринимался жертвой как подлинный «благодаря» слабости механизма аутентификации. Хакеры атаковали DNS-сервера провайдеров или крупных и мелких фирм, обращающиеся к вышестоящим DNS-серверам и кэширующие полученные от них (или от хакера) ответы. Образовывался устойчивый очаг заражения (poisoned DNS-server) – пользователь, например, пытался разрешить доменное имя www.intel.com, а попадал на сервер злоумышленника, начиненный зловредными программами. Когда же ошибки в DNS-серверах были исправлены, хакеры переключились на атаки DNS-клиентов, что оказалось намного сложнее, поскольку типичная пользовательская машина генерирует сравнительно небольшое количество DNS-запросов в единицу времени. «Скормить» ей поддельный DNS-ответ не так-то просто. Для этого необходимо знать IP-адрес оригинального DNS-сервера, номер UDP-порта источника и 16-битный идентификатор TXID (Transaction ID). В силу высокой предсказуемости двух последних значений атака на NT не представляла большой проблемы, о чем Microsoft узнала лишь в марте 2004 года, исправив ошибку в W2K SP4 и XP SP2. Точнее, она думала, что ее исправила... Согласно исследованиям Amit Klein (из компании Trusteer), Alla Berzroutchko (компания Scanit) и Roy Arends (компания Nominet UK), ошибка никуда делась, и даже самые последние версии Windows подвержены угрозе атаки. Amit Klein подробно описал технику атаки в документе «Microsoft Windows DNS Stub Resolver Cache Poisoning» вместе с исходными текстами proof-of-concept exploit'а: http://www.trusteer.com/docs/Microsoft_Windows_resolver_DNS_cache_poisoning.pdf. Ознакомившись с этим исследованием, один из сотрудников Microsoft выразил в своем блоге резкое несогласие: blogs.technet.com/swi/archive/2008/04/09/ms08-020-how-predictable-is-the-dns-transaction-id.aspx. Ну а пока между ними идут разборки, дыра попала на Security Focus: www.securityfocus.com/bid/28553/info. TargetsВся линейка NT-подобных систем по Висту включительно (32-битные и 64-битные редакции). ExploitsИсходные тексты exploit'а можно найти в статье Amit Klein'а: www.trusteer.com/docs/Microsoft_Windows_resolver_DNS_cache_poisoning.pdf. SolutionУстановить на рабочей станции свой собственный DNS-сервер (например, бесплатный SMALL HTTP), напрямую обращающийся к корневым DNS-серверам по TCP-протоколу, и заблокировать 53-UDP порт на брандмауэре для отсечения подложных DNS-ответов. Borland InterBase – удаленное переполнение буфераBrief11 апреля 2008 года была обнародована информация о дыре в популярном сервере баз данных Borland InterBase, подверженном угрозе удаленного переполнения буфера с захватом управления. Ошибку обнаружил сотрудник Oracle Corporation, довольно известный (в узких кругах) специалист по безопасности Zhen Hua Liu, живущий в своей норе на побережье Redwood'а. Исследуя дизассемблерные внутренности файла ibserver.exe, он обратил внимание на отсутствие проверки длины переданных пользователем данных перед их копированием в локальный буфер. Это подтверждает код, снабженный комментариями (ищи его на DVD). Мы имеем дело с классическим стековым переполнением (буфер-приемник находится в стеке), со всеми вытекающими. На системах с исполняемым стеком мы запросто можем подменить адрес возврата из функции, передав управление на shell-код. На системах с неисполняемым стеком – XP SP2/Server SP1 и выше при наличии аппаратной поддержки со стороны ЦП – при активном DEP'е мы можем реализовать атаку типа return2libc (по умолчанию DEP защищает только системные компоненты). Название, кстати, пришло из мира UNIX, в Windows нет libc, вместо этого там KERNEL32.DLL, но сути дела это не меняет. На системах с рандомизацией адресного пространства (Висла/Server 2008) передать управление на shell-код, скорее всего, не удастся, и жертва получит крах, ведущий к остановке сервиса «InterBase ibserver». TargetУязвимость подтверждена в Borland Interbase 2007 SP2 (ibserver.exe version 8.0.0.123). Остальные версии не проверялись, но, возможно, они также уязвимы. ExploitНиже приведен исходный код proof-of-concept exploit'а, передающий управление на shell-код. Его можно скачать по адресу: www.securityfocus.com/data/vulnerabilities/exploits/28730.pl. SolutionПроизводитель еще никак не отреагировал на сообщение о дыре и когда появится «лекарство» в виде заплатки – неизвестно. Особо озабоченные проблемой могут пропатчить код ibserver.exe, воткнув туда несколько машинных команд для выполнения проверки границ буфера. Python – удаленное переполнение буфера в библиотеке zlibBriefХакер Justin Ferguson из IOActive Security Advisory 9 апреля этого года обнародовал обнаруженную им дыру в популярной библиотеке zlib. Библиотека входит в штатный комплект поставки языка Python, приобретающего с каждым днем все большую и большую распространенность, и потому угроза вполне актуальна. «Сидит» ошибка в функции PyZlib_unflush, реализованной в файле Python-2.5.2/Modules/zlibmodule.c. Функция выполняет сброс (flush) указанного количества байт, заданного знаковым аргументом (всегда трактуемым как положительное целое без проверки на отрицательное значение; передача которого функции выделения памяти приводит к резервированию одного байта буферной памяти). А вот функция копирования данных в буфер после преобразования отрицательного знакового аргумента в беззнаковое получает очень большое число, соответствующее нескольким гигабайтам памяти. Естественно, это приводит к переполнению кучи. Дыра объявлена удаленной, хотя на самом деле она локальная. Момент требует пояснений. Да, действительно, дыра локальна по своей природе и, чтобы добиться переполнения, необходимо вызывать функцию flush(). Это можно сделать, только если запускать Python-программы на целевой машине, для чего там должен быть установлен интерпретатор языка, а хакеру – предоставлен shell с возможностью выполнения Python-программ. Но даже при таком оптимистичном раскладе злоумышленник не сможет завалить операционную систему, а только запущенный экземпляр интерпретатора. Или (в идеале) захватить управление системой без превышения уровня имеющихся у него привилегий. А оно ему надо? Так что атака носит сугубо лабораторный характер. Лишь в тех немногих случаях, когда интерпретатор Python'а запускается на более высоком уровне привилегий, хакер может поиметь с этого какую-то выгоду. Подробности на www.securityfocus.com/bid/28715. TargetДыра подтверждена в Python версии 2.5.2, остальные версии также могут быть уязвимы. ExploitИсходный текст proof-of-concept exploit'а лежит на www.securityfocus.com/data/vulnerabilities/exploits/28715.py, а ниже приведен его ключевой фрагмент: Ключевой фрагмент proof-of-concept exploit'а compMsg = zlib.compress(msg) bad = -24 decompObj = zlib.decompressobj() decompObj.decompress(compMsg) decompObj.flush(bad) SolutionРазработчики исправили ошибку, но пока только на SVN-репрозитории (bugs.python.org/issue2586). Ждем-с выхода очередной стабильной версии. Adobe Flash Player – удаленное переполнение буфераBrief9 апреля 2008 года Mark Dowd из исследовательского подразделения ISS X-Force, входящего в состав корпорации IBM, совместно с хакером wushi из группы team509 обнаружили и опубликовали дыру в Adobe Flash Player, работающем под управлением операционной системы Linux. Для реализации атаки достаточно «скормить» жертве специальным образом сконструированный swf-файл (скажем, заманив на web-страничку или послав файл почтой). Главное, чтобы Adobe Flash Player был установлен! Ошибка носит системно-независимый характер, хотя, с учетом различий реализаций под Windows и Linux, для каждой конкретной платформы требуется свой swf-файл с умышленно искаженным полем DefineSceneAndFrameLabelData.SceneCount, содержащим количество «сцен», которые необходимо считать из файла. SceneCount представляет собой двойное знаковое слово, но проверка на отрицательное значение не выполняется, и хакер получает возможность модифицировать любую (ну, или практически любую) ячейку адресного пространства внутри процесса. Это действие открывает широкие возможности для атак, особенно с учетом того, что Adobe Flash Player не использует возможности рандомизации адресного пространства, предоставляемые Вистой и некоторыми версиями Linux'а. Для захвата управления машиной (с привилегиями Flash Player'а) было бы достаточно перезаписать указатель на функцию или подменить адрес возврата, но Mark Dowd пошел намного более крутым и радикальным путем, атаковав виртуальную flash-машину, интерпретирующую байт-код и известную под именем ActionScript Virtual Machine (или, сокращенно, AVM). Достоинство такого подхода, во-первых, в его новизне, а, во-вторых, в системной независимости. Байт-код виртуальной машины не привязан к конкретной платформе, и потому однажды сконструированный exploit не нужно переписывать под всю процессорную линейку, на которой только реализован Adobe Flash Player: x86, x86-64, PPC, etc. Подробнее об этом можно прочитать в статье Mark'а Dowd'а – «Application-Specific Attacks: Leveraging the ActionScript Virtual Machine», доступной всем желающим: documents.iss.net/whitepapers/IBM_X-Force_WP_final.pdf. Также рекомендуется посетить Security Focus: www.securityfocus.com/bid/28695. TargetsAdobe Flash Player 8.0.34.0/8.0.35.0/9/9.0.115.0/9.0.28.0/9.0.31.0/9.0.45.0/9.0.47.0/9.0.48.0 (дистрибутивы RedHat Enterprise Linux Desktop/RedHat Enterprise Linux Extras/RedHat Enterprise Linux Supplementary server/S.u.S.E. Linux 10.1 ppc/S.u.S.E. Linux 10.1 x86/S.u.S.E. Linux 10.1 x86-64/S.u.S.E. Novell Linux Desktop 9/S.u.S.E. openSUSE 10.2/S.u.S.E. openSUSE 10.3 и другие). ExploitProof-of-concept exploit доступен только подписчикам «Immunity CANVAS Early Update Program». Членство обойдется в $1450 на 3 месяца (продление стоит $730 в квартал). Подробности: www.immunityinc.com/products-canvas.shtml. SolutionПроизводитель уже выпустил Flash Player 9.0.124.0, свободный от ошибки переполнения, а для старых версий доступно бесплатное обновление, выложенное на www.adobe.com/support/security/bulletins/apsb08-11.html. Однако, ни новая версия, ни обновление не исправляют всех ошибок. Проверка поля SceneCount на отрицательное значение появилась (какое огромное достижение, вах!), но дефекты виртуальной AVM-машины как были, так и остались. По-прежнему возможен обход верификатора байт-кода и прочие трюки, которым планируется посвятить отдельную статью. В этом обзоре (в связи с ограничениями по объему) мы рассмотрим непосредственно саму ошибку знакового переполнения. Full discloseДля анализа дыры в Flash-player'е, помимо самого плеера (который уже наверняка установлен в системе), нам понадобится спецификация на SWF/FLV-файлы, последнюю редакцию которой (на момент написания этих строк – 9'ю), можно скачать с сервера фирмы Macromedia: download.macromedia.com/pub/flash/licensing/file_format_specification_v9.pdf. Осторожно! При первом открытии pdf-файла эта сволочь лезет в Сеть, передавая наши данные и запрашивая сертификат. Для сохранения инкогнито рекомендуется воспользоваться брандмауэром. Спустя какое-то время Adobe Acrobat Reader сменит гнев на милость и отобразит содержимое спецификации, предварительно «выплюнув» на экран противный NAG-Screen с текстом лицензионного соглашения и стандартными кнопочками «Agree» (Принять) и «Disagree» (Послать на :)). Структура SWF-файлов состоит из последовательности различных объектов: фигур, звуков, шрифтов, текста, etc. Все они обрабатываются вполне корректно (дефектов реализации нет или таковые еще не найдены). Но вот структура DefineSceneAndFrameLabelData, описывающая сцену (Scene), подвержена целочисленному знаковому переполнению. Рассмотрим структуру DefineSceneAndFrameLabelData более подробно. Как видно, она включает в себя массив сцен Scenes. Их количество задано в переменной SceneCount типа unsigned int32 (беззнаковое двойное слово), которая лежит рядом с массивом. Теговая структура DefineSceneAndFrameLabelData (tag ID 0x56), подверженная целочисленному знаковому переполнению // вспомогательные структуры SceneData { UI32 FrameOffset String SceneName } FrameData { UI32 FrameNumber String FrameLabel } // теговая структура DefineSceneAndFrameLabelData { RecordHeader Header UI32 SceneCount SceneData Scenes[SceneCount] UI32 FrameCount FrameData Frames[FrameCount] } Теперь загрузим flash-player в дизассемблер и посмотрим на код, обрабатывающий переменную SceneCount вместе с массивом Scenes: Дизассемблерный фрагмент Flash Player'а, в котором происходит переполнение .text:30087A42 call SWF_GetEncodedInteger ; получить Scene Count .text:30087A47 mov edi, [ebp+arg_0] .text:30087A4A mov [esi+4], eax ; EAX := Scene Count .text:30087A4D mov ecx, [ebx+8] ; ECX - размер swf-файла .text:30087A50 sub ecx, [ebx+4] ; ECX - кол-во байт до конца файла .text:30087A53 cmp eax, ecx ; ?(Scene Count > ECX) .text:30087A55 jg loc_30087BB4 ; <- не выполняется, если SC < 0 .text:30087A5B test eax, eax ; проверка на нуль .text:30087A5D jz loc_30087B0E ; <- не выполняется, если SC < 0 .text:30087A63 mov ecx, [edi+20h] .text:30087A66 push 3 .text:30087A68 push 3 .text:30087A6A push 0Ch ; nCount .text:30087A6C push eax ; nSize .text:30087A6D call mem_Calloc ; обламывается, если SC < 0 .text:30087A72 push eax ; EAX := 0, если SC < 0 .text:30087A73 mov ecx, esi .text:30087A75 call sub_3004A766 ; делает разные неинтересные дела .text:30087A7A and [ebp+arg_0], 0 .text:30087A7E cmp dword ptr [esi+4], 0 .text:30087A82 jle short loc_30087AFA ; всегда выполняется Сначала переменная SceneCount сравнивается с количеством байт, оставшихся до конца swf-файла. Сравнение осуществляется при помощи машинной команды JG, интерпретирующей SceneCount как знаковую переменную. Если SceneCount < 0, эта проверка завершится успешно (для хакеров), поскольку всякое отрицательное число больше любого положительного количества байт, отличного от нуля; проверка на нулевое значение SceneCount также выполняется. Какие, однако, аккуратные программисты! Целых две проверки, и все не в тему! А дальше... SceneCount передается функции выделения памяти mem_Calloc(), интерпретирующей ее как беззнаковую переменную. Поскольку знаковый бит – самый старший бит числа, мы запрашиваем у функции mem_Calloc(), как минимум, 2 Гб памяти. Последние, естественно, не выделяются, но проверка на успешность выделения отсутствует, так как программисты по своей наивности полагают, что память – ресурс неисчерпаемый. Они заблуждаются, и в нашем случае mem_Calloc() возвращает ноль. Остается только разобраться, что делает программа с полученным указателем. А делает она с ним следующее (для краткости дизассемблерный листинг переведен в псевдокод): Псевдокод функции, позволяющей хакеру перезаписывать любую ячейку памяти .text:30087AFA mov eax, [esi+4] ; SceneCount .text:30087AFD mov ecx, [esi] ; returned pointer .text:30087AFF lea eax, [eax+eax*2] ; EAX := EAX*3 .text:30087B02 lea eax, [ecx+eax*4] ; EAX := EAX*4 + pointer .text:30087B05 mov ecx, [ebp+arg_8] ; ECX := FrameCounter (или FC) .text:30087B08 sub ecx, [eax-0Ch] ; ECX := FC-*((SC-1)*12+pointer) .text:30087B0B mov [eax-4], ecx ; *(SC*12+pointer-4) = ECX Поскольку pointer, возвращенный функцией mem_Calloc(), у нас равен нулю, мы получаем следующий псевдокод: *(SсeneCount*12-4) = FrameCount-*((SceneCount-1)*12). Если учесть, что переменные SceneCount и FrameCount представляют собой двойные слова, полностью контролируемые хакером, подбирая их различные сочетания, мы можем модифицировать различные ячейки памяти. С учетом ограничений, налагаемых данной формулой. Каких именно? Путем несложных преобразований получаем: (0x80000000 | ((address + 4)/12)), то есть можно модифицировать только те адреса, которые после добавления к ним четырех байт делятся на 12 без остатка. Не такое уж и жестокое ограничение! В подвластной нам области памяти без труда можно отыскать кучу интересных указателей на функции (например, адресов возврата). Само собой, речь идет только о модификации тех областей, что доступы на запись – стек, куча, секция данных, а также некоторые служебные структуры операционной системы, расположенные в нижней половине адресного пространства. Короче, главное фантазию иметь, а за реализацией атаки дело не станет! |