18 мая 2020 года восемнадцатилетний исследователь Билл Демиркапи опубликовал в своем блоге объемное исследование, посвященное очень любопытной теме. Автору удалось установить в Windows собственный руткит с помощью утилиты RootkitBuster компании Trend Micro. Рассказ о том, как молодой исследователь пришел к успеху, — в сегодняшней статье.
Изучая методы обнаружения руткитов, Билл Демиркапи наткнулся на бесплатную утилиту RootkitBuster компании Trend Micro. Разработчик позиционирует ее как сканер скрытых файлов, записей реестра и master boot record (MBR), предназначенный для идентификации и удаления руткитов. Описание программы гласило, что RootkitBuster способен выявлять несколько методов проникновения руткитов и закрепления их в системе. Это заинтересовало исследователя, и он решил выяснить, что у RootkitBuster спрятано под капотом. Пристальное изучение программы позволило обнаружить примечательную дыру в коде, с помощью которой можно использовать тулзу не только для поиска прячущихся в глубинах Windows вредоносов, но и для установки в систему собственных руткитов.
Эта статья опирается на оригинальный текст исследования Билла Демиркапи. Если ты в достаточной степени владеешь английским языком, то можешь ознакомиться с ней в его блоге.
Установка
Сразу после запуска инсталлятора RootkitBuster Билл обратил внимание на предупреждение Resource Hacker о том, что софтина пытается установить в его систему файл tmcomm.sys — драйвер, используемый некоторыми приложениями Trend Micro.
RootkitBuster устанавливает драйвер до того, как пользователь примет условия лицензионного соглашения (здесь и далее иллюстрации из блога Билла Демиркапи)
Примечательно, что драйвер и сам исполняемый файл сканера были распакованы на диск в папку %TEMP%RootkitBuster еще до того, как на экране Билла появился текст лицензионного соглашения. Оно, в частности, гласило, что пользователь RootkitBuster обязуется «не пытаться перепроектировать, модифицировать, дизассемблировать, декомпилировать, исследовать исходный код или создавать производные произведения на основе этой программы».
Поэтому Билл взял и завершил процесс инсталлятора с помощью пункта «Закрыть окно» контекстного меню, так и не приняв условия лицензии. Что позволило ему с чистой совестью «дизассемблировать, декомпилировать» и делать с этим продуктом Trend Micro другие вещи, о которых в приличном обществе не принято говорить вслух. Отличный трюк для обхода юридических сложностей!
Драйвер tmcomm.sys
Этот драйвер, обозначенный как Common Module Trend Micro, способен принимать сообщения от привилегированных приложений пользовательского режима и может выполнять функции, специфичные не только для утилиты RootkitBuster. Иными словами, он используется многими другими программами Trend Micro.
Создание устройства в драйвере tmcomm.sys
Билл обратил внимание на то обстоятельство, что для использования созданного драйвером виртуального устройства необходимо обладать привилегиями SYSTEM, то есть как минимум иметь в системе права администратора. Это значительно сужает возможности использования потенциальных уязвимостей в драйвере, но не исключает их.
Класс TrueApi
Если взглянуть на эту структуру внимательно, становится очевидно, что она используется в качестве альтернативы прямому вызову функций. Билл предположил, что программы Trend Micro кешируют эти импортируемые функции в момент инициализации, чтобы избежать перехватов таблицы отложенного импорта. При отложенном импорте прилинкованная DLL загружается только тогда, когда приложение обращается к одной из содержащихся в ней функций. Если в системе поселился руткит, способный перехватывать таблицу импорта в момент загрузки драйвера, необходимо предусмотреть соответствующий защитный механизм.
Класс XrayApi
В драйвере имеется еще один важный класс под названием XrayApi. Он используется для доступа к нескольким низкоуровневым устройствам и непосредственного взаимодействия с файловой системой. Этот класс содержит структуру XrayConfig, в которой сосредоточена его основная конфигурация:
В этой структуре среди прочего есть информация о расположении таких внутренних и недокументированных переменных в ядре Windows, как ExInitializeNPagedLookasideListInternal, IopRootDeviceNode, ExDeleteNPagedLookasideList и PpDevNodeLockTree. Исследователь предположил, что предназначение этого класса — получение прямого доступа к низкоуровневым устройствам в обход документированных (а следовательно, широко известных вирусописателям) методов.
Запросы IOCTL
Перед изучением возможностей и функций драйвера Билл Демиркапи уделил внимание механизму обработки запросов IOCTL. Это специфичные для отдельных (преимущественно низкоуровневых) устройств системные вызовы ввода-вывода, которые не могут быть реализованы с использованием регулярных вызовов. В основной функции диспетчеризации драйвер Trend Micro преобразует данные вместе с запросом IRP_MJ_DEVICE_CONTROL в собственную структуру, которую исследователь назвал TmIoctlRequest:
Таким образом, отправка запросов IOCTL в драйвере tmcomm.sys реализована с помощью своеобразных «таблиц диспетчеризации», при этом «базовая таблица» содержит код IOCTL и соответствующую вспомогательную функцию. Например, если необходимо отправить IOCTL-запрос с кодом 0xDEADBEEF, драйвер сравнивает запрос с каждой строкой базовой таблицы диспетчеризации и передает его только в том случае, если найдет совпадение. Каждая запись в такой таблице имеет структуру, подобную представленной ниже:
Изучая механизмы обработки запросов IOCTL, Билл Демиркапи внимательно рассмотрел каждую запись базовой таблицы диспетчеризации и хранящиеся там функции. Это, в свою очередь, позволило определить назначение вспомогательных таблиц диспетчеризации.
IoControlCode == 9000402Bh
IoControlCode == 90004027h
Эта таблица диспетчеризации преимущественно используется для управления сканером процессов. Многие функции в ней используют отдельный поток сканирования для синхронного поиска процессов с помощью различных методов, как документированных, так и недокументированных. Билл Демиркапи также собрал описания основных функций указанной таблицы.
Все эти функции используют несколько структур, которые исследователь назвал MicroTask и MicroScan. Вот как они выглядят в дизассемблированном виде.
Для большинства запросов IOCTL в этой вспомогательной таблице структура MicroScan заполняется на стороне клиента, который вызывает драйвер. Именно эту особенность Демиркапи решил использовать для эксплуатации возможной уязвимости.
Эксплоит
Билл Демиркапи признается, что во время реверсинга функций, хранящихся в этой вспомогательной таблице диспетчеризации, он был совершенно сбит с толку. В итоге оказалось, что указатель ядра MicroScan, возвращаемый такими функциями, как GetProcessesAllMethods, напрямую передавался другим функциям, например DeleteTaskResults, на стороне клиента. Эти функции принимают такой недоверенный указатель ядра и практически без проверки вызывают функции в таблице виртуальных функций, описанной в классе.