Прошло уже три дня с тех пор, как исследователь Parvez Anwar опубликовал информацию о множественных dll hijacking уязвимостях в продуктах Microsoft Office, а какой-либо реакции не наблюдается. Ни CVE, ни сообщений на специализированных ресурсах, Windows Update не качает свежих патчей. Что ж, может, так и нужно, может быть, это не уявимость, а особенность продукта?
Между тем, эксплуатация этой особенности проста и доступна даже ребенку. И, раз уж производитель пока эту «фичу» не удалил, почему бы не написать о ней небольшую статью.
Речь пойдет о Windows 7. Работает ли это на других версиях — мне на текущий момент неизвестно, нужно проверять. Принцип действия описываемого явления (как и многих других, впрочем) основан на старой доброй технологии COM/OLE/ActiveX.
Технология COM призвана воплощать ООП и повторное использование кода, позволяя любым приложениям использовать однажды созданные кем-либо классы (или компоненты), если эти классы зарегистрированы в системе. Регистрация компонента по сути представляет собой соответствующие записи в реестре. Каждому классу при его создании назначается уникальный 16-байтовый идентификатор — CLSID, который будет однозначно определять этот компонент в любое время на любом
компьютере. Глобальные идентификаторы всех зарегистрированных в системе классов содержит ветка реестра HKEY_CLASSES_ROOT\CLSID.
Исполняемый код компонента должен быть оформлен в виде библиотеки .dll (на самом деле не всегда, но для данной задачи можно упростить). Ссылка на библиотеку содержится в подключе InprocServer32 ключа реестра, соответствующего компоненту.
В случае, когда приложение хочет использовать функциональность, реализованную одним из компонентов, оно отправляет системе запрос на создание экземпляра класса (при этом передается CLSID этого класса). Если такой класс зарегистрирован, система читает реестр и подгружает нужную .dll в адресное пространство процесса, затем вызывает из этой библиотеки код, создающий нужный объект.
А что же приложения MS Office? Кроме того, что они тоже под завязку нашпигованы технологией COM (и даже сами являются COM-объектами), они еще и позволяют создавать/читать документы, содержащие элементы ActiveX.
Фактически такой документ представляет собой файл, содержащий (помимо текста, изображений, форматирования и т.п.) идентификатор компонента и некоторую информацию о свойствах встраиваемого объекта. Давайте посмотрим, как это выглядит на практике.
Открываем MS Word. Если у вас не подключена вкладка «Developer»/«Разработчик», необходимо подключить ее в настройках: File->Options->Customize Ribbon, Файл->Параметры->Настроить ленту, Файл->Параметры Word->Показывать вкладку «Разработчик» на ленте и т.п., в зависимости от того, какая версия MS Office у вас установлена.
Переходим во вкладку «Разработчик» и выбираем кнопку с молотком и гаечным ключом «Инструменты из предыдущих версий».
Затем похожую кнопку «Другие элементы управления».
В появившемся окне выберите ActiveX компонент по своему вкусу, мне нравится Microsoft Forms 2.0 Command Button.
Если открыть реестр и поискать по имени компонента, можно обнаружить, что CLSID нашего контрола
{D7053240-CE69-11CD-A777-00DD01143C57}, а библиотека, содержащая его исполняемый код — FM20.DLL.
Что же будет представлять собой документ, который мы создали? Давайте сохраним его и посмотрим.
Формат .docx это всем известный ZIP. Распаковываем любой подходящей утилитой.
Архив содержит несколько папок с файлами. Нам нужен word\activeX\activeX1.xml
Открываем его обычным текстовым редактором и видим примерно такое содержимое.
Как видно, CLSID элемента управления присутствует и легко может быть заменен.
Теперь нужно сказать пару слов о том, на что, собственно, его можно заменить, а также о том, что такое dll hijacking, и почему это все работает.
Заменить CLSID можно на CLSID любого другого элемента управления, и не только элемента управления, но и любого ActiveX, и даже не только ActiveX, но и любого COM-класса, зарегистрированного в системе (можно и на любой случайный GUID, но это ни к каким интересным последствиям не приведет).
Все дело в том, что, прочитав идентификатор из документа, MS Word передаст его системе, система прежде всего попытается подгрузить библиотеку в память процесса и вызвать из нее первые функции (DllMain, DllGetClassObject, IClassFactory::CreateInstance и т.д.). И только после этого приложение начнет выяснять, что это за библиотека, что за компонент, можно ли добавлять его в документ, и нужно это ему вообще. Запросто может оказаться, что компонент не подходит по каким-то критериям, но это выясняется уже после того, как его исполняемый код оказался в виртуальной памяти процесса и получил управление. Он не будет выгружен даже после того, как MS Word точно установил, что ему этот класс не нужен! Такое поведение приводит к целому ряду любопытных явлений, в том числе — к описываемому в данной заметке.
Теперь о dll hijacking. «Угон динамической библиотеки» — обычное, изначальное и даже в чем-то логичное поведение приложения Windows, когда оно ищет необходимую ему библиотеку в той директории, которая является для него текущей, и только затем — в определяемых настройками ОС местах. Все бы было ничего, если бы злоумышленники довольно скоро (и довольно давно) не догадались, что можно положить рядом с документом или ярлыком собственную библиотеку с таким же названием, как и у
библиотеки, которую ожидает найти приложение.
Вообще-то этой технике уже много лет, Microsoft борется с ней давно, упорно, и, как можно видеть, до сих пор не вполне результативно.
На этот раз исследователи обнаружили затерянные в недрах операционной системы Windows 7 несколько dll, которые подгружают другие dll, и ищут их — до сих пор! — в текущей директории процесса. Эти Microsoft'ом забытые оснастки для консоли управления, присадки для Oracle'а и что-то еще столь же известное и часто используемое — оказались еще и COM-классами. Которые, как вы уже догадались, мы можем встроить в обычный документ MS Office.
Вернемся к нашему MS Word и поменяем CLSID в распакованном документе на любой удобный из отчета
Parvez Anwar. Например, на первый — {394C052E-B830-11D0-9A86-00C04FD8DBF7}.
Запакуем документ (при необходимости переименуем его обратно в .docx).
Теперь нам нужна собственная dll под именем elsext.dll. Неважно, на чем вы ее создадите, главное, чтобы она имела ту же разрядность, что и пакет MS Office, была способна к загрузке, и вы могли бы добавить свой код в DllMain или DllGetClassObject. Я возьму старый добрый VC6 — у меня 32хбитный офис.
Осталось положить нашу elsext.dll в одну директорию (можно в общей сетевой папке) с модифицированным документом и попросить пользователя этот документ открыть/прочитать.
Еще один момент: с dll hijacking, как вы помните, Microsoft борется. Поэтому при запуске MS Word меняет текущую директорию на «Документы» текущего пользователя. К сожалению (или к счастью) при вызове приложения для открытия документа (например, двойным щелчком в explorer) MS Word сначала пытается открыть документ со всеми вытекающими последствиями, и только потом изменяет свою текущую директорию на «Документы». Отсюда вытекает тот факт, что наша dll будет подгружена только в том случае, если пользователь открыл документ двойным щелчком, и MS Word не был до этого запущен (иначе загрузится elsext.dll из system32).
Между тем, эксплуатация этой особенности проста и доступна даже ребенку. И, раз уж производитель пока эту «фичу» не удалил, почему бы не написать о ней небольшую статью.
Речь пойдет о Windows 7. Работает ли это на других версиях — мне на текущий момент неизвестно, нужно проверять. Принцип действия описываемого явления (как и многих других, впрочем) основан на старой доброй технологии COM/OLE/ActiveX.
Технология COM призвана воплощать ООП и повторное использование кода, позволяя любым приложениям использовать однажды созданные кем-либо классы (или компоненты), если эти классы зарегистрированы в системе. Регистрация компонента по сути представляет собой соответствующие записи в реестре. Каждому классу при его создании назначается уникальный 16-байтовый идентификатор — CLSID, который будет однозначно определять этот компонент в любое время на любом
компьютере. Глобальные идентификаторы всех зарегистрированных в системе классов содержит ветка реестра HKEY_CLASSES_ROOT\CLSID.
Исполняемый код компонента должен быть оформлен в виде библиотеки .dll (на самом деле не всегда, но для данной задачи можно упростить). Ссылка на библиотеку содержится в подключе InprocServer32 ключа реестра, соответствующего компоненту.
В случае, когда приложение хочет использовать функциональность, реализованную одним из компонентов, оно отправляет системе запрос на создание экземпляра класса (при этом передается CLSID этого класса). Если такой класс зарегистрирован, система читает реестр и подгружает нужную .dll в адресное пространство процесса, затем вызывает из этой библиотеки код, создающий нужный объект.
А что же приложения MS Office? Кроме того, что они тоже под завязку нашпигованы технологией COM (и даже сами являются COM-объектами), они еще и позволяют создавать/читать документы, содержащие элементы ActiveX.
Фактически такой документ представляет собой файл, содержащий (помимо текста, изображений, форматирования и т.п.) идентификатор компонента и некоторую информацию о свойствах встраиваемого объекта. Давайте посмотрим, как это выглядит на практике.
Открываем MS Word. Если у вас не подключена вкладка «Developer»/«Разработчик», необходимо подключить ее в настройках: File->Options->Customize Ribbon, Файл->Параметры->Настроить ленту, Файл->Параметры Word->Показывать вкладку «Разработчик» на ленте и т.п., в зависимости от того, какая версия MS Office у вас установлена.
Переходим во вкладку «Разработчик» и выбираем кнопку с молотком и гаечным ключом «Инструменты из предыдущих версий».
Затем похожую кнопку «Другие элементы управления».
В появившемся окне выберите ActiveX компонент по своему вкусу, мне нравится Microsoft Forms 2.0 Command Button.
Если открыть реестр и поискать по имени компонента, можно обнаружить, что CLSID нашего контрола
{D7053240-CE69-11CD-A777-00DD01143C57}, а библиотека, содержащая его исполняемый код — FM20.DLL.
Что же будет представлять собой документ, который мы создали? Давайте сохраним его и посмотрим.
Формат .docx это всем известный ZIP. Распаковываем любой подходящей утилитой.
Архив содержит несколько папок с файлами. Нам нужен word\activeX\activeX1.xml
Открываем его обычным текстовым редактором и видим примерно такое содержимое.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ax:ocx ax:classid="{D7053240-CE69-11CD-A777-00DD01143C57}" ax:persistence="persistStorage" r:id="rId1" xmlns:ax="http://schemas.microsoft.com/office/2006/activeX" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>
Как видно, CLSID элемента управления присутствует и легко может быть заменен.
Теперь нужно сказать пару слов о том, на что, собственно, его можно заменить, а также о том, что такое dll hijacking, и почему это все работает.
Заменить CLSID можно на CLSID любого другого элемента управления, и не только элемента управления, но и любого ActiveX, и даже не только ActiveX, но и любого COM-класса, зарегистрированного в системе (можно и на любой случайный GUID, но это ни к каким интересным последствиям не приведет).
Все дело в том, что, прочитав идентификатор из документа, MS Word передаст его системе, система прежде всего попытается подгрузить библиотеку в память процесса и вызвать из нее первые функции (DllMain, DllGetClassObject, IClassFactory::CreateInstance и т.д.). И только после этого приложение начнет выяснять, что это за библиотека, что за компонент, можно ли добавлять его в документ, и нужно это ему вообще. Запросто может оказаться, что компонент не подходит по каким-то критериям, но это выясняется уже после того, как его исполняемый код оказался в виртуальной памяти процесса и получил управление. Он не будет выгружен даже после того, как MS Word точно установил, что ему этот класс не нужен! Такое поведение приводит к целому ряду любопытных явлений, в том числе — к описываемому в данной заметке.
Теперь о dll hijacking. «Угон динамической библиотеки» — обычное, изначальное и даже в чем-то логичное поведение приложения Windows, когда оно ищет необходимую ему библиотеку в той директории, которая является для него текущей, и только затем — в определяемых настройками ОС местах. Все бы было ничего, если бы злоумышленники довольно скоро (и довольно давно) не догадались, что можно положить рядом с документом или ярлыком собственную библиотеку с таким же названием, как и у
библиотеки, которую ожидает найти приложение.
Вообще-то этой технике уже много лет, Microsoft борется с ней давно, упорно, и, как можно видеть, до сих пор не вполне результативно.
На этот раз исследователи обнаружили затерянные в недрах операционной системы Windows 7 несколько dll, которые подгружают другие dll, и ищут их — до сих пор! — в текущей директории процесса. Эти Microsoft'ом забытые оснастки для консоли управления, присадки для Oracle'а и что-то еще столь же известное и часто используемое — оказались еще и COM-классами. Которые, как вы уже догадались, мы можем встроить в обычный документ MS Office.
Вернемся к нашему MS Word и поменяем CLSID в распакованном документе на любой удобный из отчета
Parvez Anwar. Например, на первый — {394C052E-B830-11D0-9A86-00C04FD8DBF7}.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ax:ocx ax:classid="{394C052E-B830-11D0-9A86-00C04FD8DBF7}" ax:persistence="persistStorage" r:id="rId1" xmlns:ax="http://schemas.microsoft.com/office/2006/activeX" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>
Запакуем документ (при необходимости переименуем его обратно в .docx).
Теперь нам нужна собственная dll под именем elsext.dll. Неважно, на чем вы ее создадите, главное, чтобы она имела ту же разрядность, что и пакет MS Office, была способна к загрузке, и вы могли бы добавить свой код в DllMain или DllGetClassObject. Я возьму старый добрый VC6 — у меня 32хбитный офис.
#include <windows.h>
int __stdcall DllMain (HANDLE, DWORD, LPVOID)
{
MessageBox (0, "Hello Habrahabr!", 0, MB_ICONEXCLAMATION);
return true;
}
Осталось положить нашу elsext.dll в одну директорию (можно в общей сетевой папке) с модифицированным документом и попросить пользователя этот документ открыть/прочитать.
Еще один момент: с dll hijacking, как вы помните, Microsoft борется. Поэтому при запуске MS Word меняет текущую директорию на «Документы» текущего пользователя. К сожалению (или к счастью) при вызове приложения для открытия документа (например, двойным щелчком в explorer) MS Word сначала пытается открыть документ со всеми вытекающими последствиями, и только потом изменяет свою текущую директорию на «Документы». Отсюда вытекает тот факт, что наша dll будет подгружена только в том случае, если пользователь открыл документ двойным щелчком, и MS Word не был до этого запущен (иначе загрузится elsext.dll из system32).