Admin
Администратор
Начиная с июля 2022 года процесс Windows CSRSS стал известен сообществу информационной безопасности как источник нескольких локальных уязвимостей повышения привилегий в Microsoft Windows. Первая публичная информация появилась 12 июля с выходом патча для CVE-2022-22047, которую активно эксплуатировали. Вскоре после этого Microsoft опубликовала статью с некоторыми техническими подробностями и раскрытием того, что субъектом угрозы была австрийская группа хакеров, которую Microsoft отслеживала как KNOTWEED. К счастью, эти разработки совпали с тесно связанными исследованиями, которые я проводил, и в том же месяце я сообщил Microsoft о двух дополнительных уязвимостях, затрагивающих тот же компонент. Теперь они исправлены как CVE-2022-37987 и CVE-2022-37989 соответственно. Все эти ошибки, широко известные как ошибки «CSRSS», лучше всего рассматривать как примеры нового класса уязвимостей повышения привилегий: отравление кэша контекста активации. В этой статье мы подробно опишем этот новый класс ошибок. Затем мы рассмотрим сильные и слабые стороны изменений кода, которые внесла Microsoft.
Понимание контекстов активации
Для начала мы должны понять некоторые основы контекстов активации.
Существуют различные API-интерфейсы Windows, которые процесс может использовать для загрузки дополнительных компонентов. Два наиболее важных из них предназначены (LoadLibrary) для загрузки библиотек DLL и CoCreateInstance для создания экземпляров COM-компонентов. В целях этого обсуждения мы сосредоточимся в первую очередь на LoadLibrary, но параллельные соображения применимы и к CoCreateInstance. Кроме того, то, что применимо к LoadLibrary в равной степени применимо и к неявной загрузке DLL через компоновку.
LoadLibrary может вызываться как с абсолютным, так и с относительным путем, но в любом случае остается неясность в отношении того, какую версию запрошенной библиотеки DLL следует загрузить. Например, даже если приложение специально запрашивает C:\Windows\System32\comctl32.dll, нет гарантии, что comctl32.dll в настоящее время установленная в этом месте на локальном компьютере и версия является той, которую задумал автор приложения. Это один из основных вариантов использования контекстов активации. Контекст активации определяется как состояние, которое Windows использует для разрешения («привязки») ссылки компонента на соответствующую версию компонента. Каждый поток всегда имеет ровно один активный контекст («активный») в любой момент времени. Для разрешения ссылки Windows использует текущий активный контекст активации.
Чтобы указать данные контекста активации для потока, код может использовать API контекста активации. Однако гораздо чаще контекст активации указывается декларативно путем развертывания манифеста. Манифест имеет форму данных XML. Обычно он встроен как ресурс в EXE или DLL, хотя Windows альтернативно будет искать файл .manifest родственный EXE, при запуске.
Давайте посмотрим на репрезентативный пример манифеста. Следующий манифест найден как ресурс в notepad.exe Windows 10 22H2 19045.2251 x64:
Этот манифест определяет контекст активации, который будет активирован при запуске notepad.exe. Обратите внимание на <dependency> элемент. Он объявляет, что указанная версия сборки ( Microsoft.Windows.Common-Controls, версия 6.0.0.0) должна быть включена. Это можно найти в C:\Windows\WinSxS. После проверки Windows обнаружит приемлемое совпадение, имея собственный манифест по адресу C:\Windows\WinSxS\Manifests\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e.manifest:
Элемент <file name="comctl32.dll" указывает, что файл с таким именем является частью сборки Microsoft.Windows.Common-Controls.Windows найдет его в соответствующем месте C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e\comctl32.dll. (Обратите внимание, что WinSxS это специальная папка с уникальной структурой.)
В целом, эти манифесты устанавливают контекст активации для notepad.exe, так что при notepad.exe загрузке comctl32.dll(через компоновку или явный вызов ) будет найдена соответствующая версия .comctl32.dll
На тему контекстов активации можно еще многое обсудить. Лучший универсальный ресурс по теме, который я нашел, — это статья здесь (https://omnicognate.wordpress.com/2009/10/05/winsxs/). Детали, представленные выше, тем не менее, должны быть достаточными для наших нынешних целей.
Кэш контекста активации
Процедура обнаружения манифестов, их синтаксического анализа и проверки их зависимостей, которые сами по себе должны обрабатываться рекурсивно, довольно интенсивна как с точки зрения вычислительных шагов, так и с точки зрения доступа к диску. По этой причине Microsoft представила механизм кэширования. Естественно, чтобы кеш обеспечивал выигрыш в производительности, он должен быть способен сохраняться за пределами времени жизни одного процесса, чтобы кешированные результаты можно было повторно использовать. Вероятно, именно по этой причине создание контекста активации не происходит внутри процесса, а делегируется процессу сеанса CSRSS.EXE. В приведенном выше примере notepad.exe процесс начнется с межпроцессного вызова CSRSS.EXE для создания контекста активации. CSRSS.EXE выполняет все необходимые шаги проверки и помещает результаты в структуру контекста активации в памяти. Он передает эту структуру обратно вызывающей стороне. Когда процессу необходимо загрузить модуль, такой как comctl32.dll, он обращается к этой структуре контекста активации в памяти, чтобы правильно направить загрузку библиотеки. Помимо возврата вызывающей стороне структуры контекста активации CSRSS.EXE сохраняет копию в кэше. Кэш вступает в игру при следующем запуске notepad.exe. Затем идет вызов CSRSS.EXE для создания контекста активации , CSRSS.EXE не нужно выполнять столько шагов, чтобы исследовать манифесты на диске и анализировать их. Вместо этого он извлекает контекст активации, ранее сохраненный в кэше. Чтобы убедиться, что кэшированные данные все еще действительны, нужно только проверить, не изменилось ли время модификации файла notepad.exe (хотя я намеренно опускаю некоторые менее важные детали для простоты).
В каждой записи кэша CSRSS хранится время модификации исполняемого файла, чтобы впоследствии можно было определить, действительна ли запись кэша, как я только что объяснил. Он также хранит 128-битное значение FILE_ID_INFORMATION, сгенерированное NTFS, которое служит гарантированным уникальным идентификатором файла. Это служит для предотвращения ошибок канонизации, при которых один и тот же текстовый путь может разрешаться в два разных файла из-за изменений в символических ссылках.
Однако, как это случается слишком часто, и несмотря на вышеуказанные меры предосторожности, внедрение кэширования сопряжено с серьезными рисками.
Опасность отравления кеша
Если кэш содержит неверные данные, выполнение любого процесса, использующего эти данные, может быть скомпрометировано. Например, неверные («отравленные») данные в кэше контекста активации могут привести к загрузке произвольной библиотеки DLL в привилегированный процесс, что приведет к повышению привилегий.
Как кэш может стать отравленным? Одна из проблем с архитектурой контекстов активации заключается в том, что, CSRSS.EXE выполняя генерацию и кэширование контекста активации, она делает это в интересах клиентского (вызывающего) процесса. Какой бы контекст активации ни хотел создать клиент, задача CSRSS создать этот контекст. Я предполагаю, что именно по этой причине поддерживаемый интерфейс CSRSS является довольно разрешительным, позволяя клиентскому процессу указать точный XML-файл манифеста, который будет проанализирован. Это имеет смысл, когда CSRSS рассматривается как сервер, действующий от имени клиента. Но когда в дело вступает кэширование, такое расположение становится токсичным. Контекст активации, сгенерированный из произвольного XML-файла манифеста, предоставленного клиентом, становится полупостоянной частью функционирования системы и позже может влиять на выполнение более привилегированного процесса.
CVE-2022-22047: KNOTWEED использует отравление кэша
Это подход, который был использован кодом эксплойта, найденным в дикой природе, происходящим от хакерской группы KNOTWEED. Эксплойт создает вызов в CSRSS. Вызов запрашивает контекст активации для привилегированного исполняемого файла и указывает вредоносный манифест. В манифесте используется недокументированный XML-атрибут манифеста с именем loadFrom. Этот атрибут разрешает неограниченное перенаправление DLL в любое место на диске, включая места за пределами обычного исправления поиска (обычным путем поиска является папка исполняемого файла и его подпапки, в дополнение к общим сборкам, установленным в C:\Windows\WinSxS: )
Манифест, показанный на рис. 3, указывает, что все запросы на загрузку библиотеки advapi32.dll должны вместо этого загружать файлы c:\repro\payload.dll. После создания запрошенного контекста активации CSRSS.EXE заносит его в кеш. При последующем запуске целевого исполняемого файла CSRSS.EXE предоставляет целевому процессу кэшированный контекст активации. Таким образом, когда привилегированный процесс попытается загрузить модуль advapi32.dll, от которого он зависит, вместо этого загрузится код злоумышленника.
Для проведения этой атаки единственным условием злоумышленника является возможность записать файл payload.dll где-нибудь в файловой системе. Чтобы убедиться, что кеш будет затронут, код эксплойта может сначала заполнить CSRSS запросы на очистку всех существующих записей в кеше и завершить одним последним сообщением о создании новой зараженной записи для целевого исполняемого файла.
Обратите внимание, что злоумышленник должен выбрать цель с высокими привилегиями, но работающую в том же сеансе, что и интерактивный пользователь (обычно это сеанс 1, когда есть только один интерактивный пользователь). Это связано с тем, что на сеанс приходится один CSRSS.EXE процесс и, следовательно, один кэш контекста активации на сеанс. Общий кэш на уровне сеанса делает атаку возможной.
Microsoft исправила это как CVE-2022-22047 в июльских исправлениях 2022 года, но исправление было чрезвычайно узким. Это касалось только использования недокументированного атрибута loadFrom. После исправления код в sxs.dll!CDllRedir::ContributorCallback, который обрабатывает перенаправления DLL, указанные с помощью loadFrom, устанавливает новый определенный флаг в контексте активации, указывающий, что контекст активации содержит перенаправление DLL. При проверке этого флага CSRSSлюбой такой контекст активации теперь будет рассматриваться как некэшируемый. Логика, управляющая тем, какие контексты активации вставляются в кеш, находится в sxssrv.dll!BaseSrvSxsCreateActivationContextFromStructEx.
Однако этот участок был слишком узким. Отравление кеша контекста активации может быть выполнено другими способами, кроме использования атрибута loadFrom, как мы сейчас увидим.
CVE-2022-37989: Обход исправления для эксплойта KNOTWEED
Изучив патч для эксплойта KNOTWEED, я понял, что его использование, вероятно, не единственный способ написать вредоносный манифест, внедряющий произвольный код в целевой процесс. Действительно, я быстро обнаружил, что могу написать манифест, внедряющий код с помощью другой техники: объявить зависимую сборку, которая находится в части файловой системы, контролируемой злоумышленником:
Вредоносный манифест, показанный на рисунке 4, приводит CSRSS к загрузке второго манифеста для именованной зависимости, который он находит в месте, контролируемом злоумышленником C:\pwn\pwn.MANIFEST:
Здесь advapi32.dll— имя DLL, необходимое целевому процессу. В результате комбинации этих двух манифестов при загрузке целевого процесса advapi32.dllDLL будет загружаться из места, контролируемого злоумышленником, C:\pwn\а не из законного места C:\Windows\System32\. Как и прежде, локальное повышение привилегий происходит, когда целевой процесс с высокими привилегиями запускается в рамках сеанса текущего пользователя.
Microsoft исправила этот вариант в октябре 2022 года как CVE-2022-37989. Патч был аналогичен патчу для оригинального эксплойта KNOTWEED. На этот раз основное изменение кода было в sxs.dll!CNodeFactory::XMLParser_Element_doc_assembly_dependency_dependentAssembly_assemblyIdentity, который обрабатывает assemblyIdentity подэлемент элемента dependentAssembly. После исправления код этой функции проверяет, содержит ли имя зависимости какие-либо прямые или обратные косые черты. Если это так, он устанавливает другой вновь определенный флаг, очень похожий на новый флаг, представленный в патче для CVE-2022-37989.sxssrv.dll!BaseSrvSxsCreateActivationContextFromStructEx распознает контексты активации, для которых установлен этот флаг, и не помещает их в кеш.
Сомнительно, чтобы элемент dependentAssembly содержал обход каталога. Тем не менее Microsoft решила и дальше поддерживать такое поведение, возможно, ради обратной совместимости. В качестве разумного компромисса они сделали контексты активации некэшируемыми, когда они полагаются на это поведение.
CVE-2022-37987: новый вектор отравления кэша контекста активации
Обе рассмотренные выше атаки работают путем создания сообщений для CSRSS создания настроенного вредоносного контекста активации, который отличается от законного контекста активации, который обычно создается путем чтения XML-файла манифеста с диска. Удивительно, что CSRSS был спроектирован так, чтобы принимать такие конфиденциальные данные от ненадежных клиентов. Как я упоминал ранее, это можно рассматривать как разумный дизайн, если вы рассматриваете CSRSS просто как предоставление услуги клиенту. С этой точки зрения клиент должен иметь возможность указать любые детали контекста активации, которые он пожелает. Проблема возникает из-за кэширования: созданные данные из ненадежного процесса могут повлиять не только на этого клиента, но и на других клиентов, которые обращаются к CSRSS впоследствии.
Однако, как это бывает, существует совершенно отдельный вектор для внедрения произвольных данных контекста активации в CSRSS, который не имеет никакого отношения к раскрываемому интерфейсу CSRSS.
Проблема возникает из-за того, что многие обращения к своей файловой системе CSRSS.EXE выполняются, выдавая себя за вызывающего. Я считаю, что это неизбежно, потому что CSRSS необходимо создать точный контекст активации на основе того, как вызывающая сторона будет просматривать файловую систему.
Что, однако, не так широко признано, так это то, насколько сильно может выглядеть файловая система при работе под олицетворением. В частности: непривилегированный процесс может перенаправить устройство DOS, создав символическую ссылку пространства имен объектов. Например, если процесс создает символическую ссылку from \??\C:to \GLOBAL??\C:\evil, то все обращения к файловой системе с корнем C:\ вместо этого перенаправляются в корень C:\evil. Перенаправление не ограничивается процессом, который создает символическую ссылку. Скорее, это влияет на весь сеанс входа в систему. (Понятие «сеанс входа» не связано с понятием сеансов Windows. См. здесь (https://learn.microsoft.com/en-us/w...s/kernel/local-and-global-ms-dos-device-names) и здесь (https://learn.microsoft.com/en-us/windows/win32/secauthn/lsa-logon-sessions) для объяснения сеансов входа в систему.) Не только это, но и если процесс с более высоким уровнем привилегий олицетворяет токен, для которого активна символическая ссылка, привилегированный процесс также видит фиктивную файловую систему. Это верно, даже если привилегированный процесс находится в другом сеансе Windows, например, сеансе 0.
Если это пугает вас, так и должно быть. Джеймс Форшоу еще в 2015 году обнаружил, что это создает огромную дыру в безопасности - (https://bugs.chromium.org/p/project-zero/issues/detail?id=240). Каждый раз, когда привилегированный процесс олицетворяет пользователя, и привилегированный процесс загружает библиотеку (или на него можно повлиять, чтобы загрузить библиотеку) во время выполнения этого олицетворения, этот привилегированный процесс может быть полностью скомпрометирован. Все, что нужно сделать злоумышленнику, — это перенаправить C:\ в поддельное место, где привилегированный процесс подберет вредоносную версию запрошенной библиотеки.
Чтобы исправить эту дыру в безопасности, Microsoft была вынуждена добавить новый флаг атрибута объекта, распознаваемый NtOpenFile(и аналогичными API), предписывающий ядру игнорировать любые перенаправления устройств DOS, исходящие из токена олицетворения. В конце концов, Microsoft публично задокументировала этот флаг как OBJ_IGNORE_IMPERSONATED_DEVICEMAP. Вы можете найти его использование в коде загрузчика в этой выдержке из ntdll!LdrpMapDllNtFileName( ntdll.dll10.0.19041.2130, уровень патча от октября 2022 г.):
Напротив, CSRSS до уровня исправления от декабря 2022 года этот флаг все еще не использовался OBJ_IGNORE_IMPERSONATED_DEVICEMAP. Таким образом, те операции с файловой системой CSRSS, которые выполняются под олицетворением, по-прежнему уязвимы для манипуляций со стороны злоумышленника, который устанавливает перенаправление устройства DOS.
Мы можем использовать это поведение, установив перенаправление для устройства C:\ во время выполнения операций зондирования. Перенаправление приведет CSRSS к фиктивной папке C:\Windows\WinSxS\, где мы можем разместить созданные манифесты. CSRSS будет кэшировать контекст активации, созданный из созданного манифеста, после чего локальная эскалация привилегий может продолжаться так же, как и в других атаках, описанных выше.
Например, предположим, что мы создали поддельный корень в C:\ActCtX\. (Название ActCtX произвольное) Внутри C:\ActCtX мы можем поместить фальшивую папку Windows\WinSxS, содержащую созданную копию параллельной сборки Microsoft.Windows.GdiPlus. Вредоносная копия идентична оригиналу, за исключением добавления одной зависимости в манифест:
Это заставляет CSRSS думать, что Microsoft.Windows.GdiPlus имеет зависимость от сборки с именем ActCtX, расположенной в корне файловой системы. Поскольку он будет искать эту сборку, нам нужно поместить ее туда:
Обратите внимание, что мы перетаскиваем этот манифест в папку C:\ActCtX\ActCtX\ActCtX.MANIFEST с дополнительной папкой, указанной ActCtXв пути. Это компенсирует тот факт, что CSRSS будет обращаться к этому манифесту, пока действует перенаправление устройства DOS. Спасибо Оливеру Ляку (@ly4k_) за проработку деталей необходимой структуры папок.
Общий эффект этих манифестов заключается в том, что создается контекст активации, указывающий, что любая загрузка advapi32.dll должна быть загружена из местоположения, контролируемого злоумышленником C:\ActCtX\advapi32.dll. CSRSS будет кэшировать этот контекст активации. Когда кэшированный контекст активации повторно используется для привилегированного процесса в том же сеансе, загрузка DLL advapi32.dll вместо этого загрузит код злоумышленника в процесс, тем самым достигнув повышения привилегий до NT AUTHORITY\SYSTEM.
Microsoft исправила это в октябре 2022 года как CVE-2022-37987. Патч состоит из изменений в sxssrv.dll!BaseSrvSxsCreateActivationContextFromMessage. В этой функции код извлекает FILE_ID_INFORMATION файл EXE или DLL, для которого создается контекст активации CSRSS. Это значение становится частью ключа кэша. Ранее мы упоминали, почему это важная мера предосторожности, позволяющая гарантировать, что контекст активации, созданный для одного исполняемого файла, не будет впоследствии извлечен из кэша и применен к другому исполняемому файлу. До исправления NtQueryInformationFile операция извлечения значения FILE_ID_INFORMATION не выполнялась под олицетворением. Следовательно, когда злоумышленник создает запись в кэше, например, для C:\Windows\System32\SomePrivilegedExecutable.exe даже если злоумышленник перенаправляется с C:\ C:\evil, результирующая запись в кэше будет применяться к законному C:\Windows\System32\SomePrivilegedExecutable.exe в отличие от C:\evil\Windows\System32\SomePrivilegedExecutable.exe. Последний был бы бесполезен для злоумышленника, потому что C:\evil\Windows\System32\SomePrivilegedExecutable.exe это не исполняемый файл, который когда-либо будет запущен как привилегированный процесс. Патч Microsoft должен был добавить олицетворение во время вызова для получения файла FILE_ID_INFORMATION. Намерение этого изменения, по-видимому, заключалось в том, чтобы любой контекст активации, сгенерированный во время перенаправления DOS-устройства, применялся только к поддельному файлу и никогда к легитимному.
Как только я изучил этот патч, я весьма скептически отнесся к его эффективности, и после дальнейшего анализа и экспериментов я пришел к выводу, что мой скептицизм оправдан. К сожалению, патч ничего не дает. Злоумышленник может обойти его, просто удалив перенаправление устройств DOS на время операции NtQueryInformationFileи вернув перенаправление устройств DOS сразу же после этого. С помощью этой корректировки все можно заставить снова работать точно так же, как это работало до патча. Кроме того, я обнаружил, что злоумышленник может надежно определить точное время для отмены и восстановления перенаправления с помощью oplock.
Тем не менее причин для паники нет. Во-первых, следует отметить, что в декабре 2022 года Microsoft дополнила свой патч для CVE-2022-37987, добавив флаг использования OBJ_IGNORE_IMPERSONATED_DEVICEMAP во время проверки манифеста. Более того, хотя оригинальный патч для CVE-2022-37987 можно было легко обойти, это не обязательно означало, что атаку можно было снова запустить. Причина в том, что показанная здесь атака основана на обходе каталога внутри элемента dependentAssembly, и этот метод был эффективно заблокирован патчем для CVE-2022-37989, который обсуждался ранее. Вместо этого вы можете запросить перенаправление DLL с помощью атрибут loadFrom, но тогда вы будете аналогичным образом заблокированы патчем CVE-2022-22047. Можно попробовать и другие функции манифеста, но на данный момент я не вижу очевидных путей к выполнению произвольного кода. Можно указать перенаправление COM-класса через элемент comClass, чтобы вызвать непредвиденную загрузку DLL в привилегированный процесс, но это будет ограничено DLL, уже существующими в безопасном месте (например, System32). Это может привести к сбою в привилегированном процессе, но эксплуатация для выполнения произвольного кода остается чрезвычайно сложной. Определение того, остаются ли какие-либо потенциально опасные функции файлов манифеста неисправленными, является интересным открытым исследовательским вопросом.
Существует еще одна причина, по которой угроза локального повышения привилегий с использованием отравления кэша контекста активации теперь значительно снижена: Microsoft ввела общую защиту.
Снижение угрозы отравления кэша контекста активации
В дополнение к конкретным исправлениям от июля 2022 г., октябрю и декабрю 2022 г., описанным выше, в октябре 2022 г. Microsoft мудро добавила общее средство защиты.
Начиная с патча от октября 2022 года, значение уровня целостности теперь хранится вместе с каждой записью кэша. Например, обычный непривилегированный процесс, работающий в рамках интерактивного сеанса, имеет уровень целостности Medium (десятичное число 8192, шестнадцатеричное число 0x2000). Если этот процесс вызывает CSRSS для создания контекста активации и CSRSS создает новую соответствующую запись кэша, запись кэша будет помечена 0x2000 (средний) в качестве уровня целостности. Впоследствии, если другой процесс, работающий со средней или более низкой целостностью, вызывается CSRSS для создания контекста активации для того же исполняемого файла, CSRSS удовлетворит запрос из кэша. Напротив, если процесс, работающий с уровнем целостности выше среднего, делает такой запрос, CSRSS будет рассматривать его как промах кэша. В этом случае CSRSS создаст контекст активации с нуля и удалит существующую запись кэша, заменив ее новой, имеющей более высокую метку целостности. Эта логика содержится в sxssrv!BaseSrvSxsCreateActivationContextFromStructEx.
Эта защита очень полезна. Это чрезвычайно сокращает диапазон сценариев, в которых кеш может быть средством повышения привилегий. Например, в атаке KNOTWORM и во всех вариантах, описанных выше, процесс, запущенный как Medium, создает вредоносную запись в кэше, которая позже будет обнаружена процессом, работающим в NT AUTHORITY\SYSTEM сеансе пользователя. Насколько мне известно, при стандартной установке Windows все процессы, запускаемые в рамках NT AUTHORITY\SYSTEM интерактивного сеанса, имеют уровень целостности System (десятичное число 16384, шестнадцатеричное число 0x4000). Таким образом, благодаря этой защите, когда придет время для извлечения записи кэша для использования привилегированным процессом, запись CSRSS с более низкой целостностью будет отброшена, так что привилегированный процесс останется полностью незатронутым ею.
Эта защита не является панацеей. Отравление кеша контекста активации остается жизнеспособным методом атаки, но только в очень ограниченном наборе обстоятельств. Напомним, что на сеанс приходится один процесс CSRSS.EXE, поэтому по своей природе кеш является сеансовым. Добавьте к этому ограничение, налагаемое мерой, заключающееся в том, что запись кэша, созданная процессом с более низким уровнем целостности, никогда не будет подхвачена процессом с более высоким уровнем целостности. Остается небольшое подмножество сценариев повышения привилегий, которые обходят эти ограничения. Я приведу два примера:
• Процесс службы Dnscache (также известный как «DNS-клиент») работает как NETWORK SERVICE, но SeImpersonatePrivilege удален из своего токена. Технически это делает Dnscache процесс с низким уровнем привилегий. Если злоумышленник скомпрометирует этот процесс, обычно не так просто перейти к NT AUTHORITY\SYSTEM. Тем не менее, поскольку процесс выполняется с целостностью системы (не путать с NT AUTHORITY\SYSTEM), а его сеанс является сеансом 0, вредоносный код, работающий внутри, Dnscache может отравить кэш контекста активации, чтобы скомпрометировать любую службу, работающую в сеансе 0, как NT AUTHORITY\SYSTEM. Обратите внимание, однако, что для завершения повышения привилегий также необходимо найти неисправленную функцию манифеста, как обсуждалось ранее.
• dwm.exe - это процесс, который выполняется в каждом интерактивном сеансе. Он работает как интерактивный пользователь, но с целостностью системы. Таким образом, злоумышленник, выполнивший код, сможет создать запись в кэше с уровнем целостности системы, которая будет подхвачена процессами с высоким уровнем привилегий, которые также выполняются в рамках интерактивного сеанса, как и в исходной атаке KNOTWEED. Примечательно, что был отчет о вероятной компрометации, dwm.exe используемой цепочкой эксплойтов в дикой природе, хотя, поскольку этот отчет предшествует защите кэша, злоумышленник в этом случае должен был преследовать другую цель при компрометации dwm.exe. Опять же, чтобы завершить повышение привилегий, необходимо найти неисправленную функцию манифеста.
Заключение
Мы раскрыли новый класс ошибок в Microsoft Windows, который мы называем отравлением кэша контекста активации. Успешная эксплуатация обычно приводит к повышению привилегий, как это достигается в дикой природе группой KNOTWEED. Все уязвимости, недавно обнаруженные как уязвимости «CSRSS», попадают в этот новый класс ошибок. Хотя корпорация Майкрософт уже выпустила общее средство защиты, остаются краеугольные случаи, выходящие за рамки меры защиты. Остается открытым исследовательский вопрос, достаточно ли специальных исправлений Microsoft для известных уязвимостей, чтобы обеспечить безопасное кэширование контекстов активации между процессами.
Понимание контекстов активации
Для начала мы должны понять некоторые основы контекстов активации.
Существуют различные API-интерфейсы Windows, которые процесс может использовать для загрузки дополнительных компонентов. Два наиболее важных из них предназначены (LoadLibrary) для загрузки библиотек DLL и CoCreateInstance для создания экземпляров COM-компонентов. В целях этого обсуждения мы сосредоточимся в первую очередь на LoadLibrary, но параллельные соображения применимы и к CoCreateInstance. Кроме того, то, что применимо к LoadLibrary в равной степени применимо и к неявной загрузке DLL через компоновку.
LoadLibrary может вызываться как с абсолютным, так и с относительным путем, но в любом случае остается неясность в отношении того, какую версию запрошенной библиотеки DLL следует загрузить. Например, даже если приложение специально запрашивает C:\Windows\System32\comctl32.dll, нет гарантии, что comctl32.dll в настоящее время установленная в этом месте на локальном компьютере и версия является той, которую задумал автор приложения. Это один из основных вариантов использования контекстов активации. Контекст активации определяется как состояние, которое Windows использует для разрешения («привязки») ссылки компонента на соответствующую версию компонента. Каждый поток всегда имеет ровно один активный контекст («активный») в любой момент времени. Для разрешения ссылки Windows использует текущий активный контекст активации.
Чтобы указать данные контекста активации для потока, код может использовать API контекста активации. Однако гораздо чаще контекст активации указывается декларативно путем развертывания манифеста. Манифест имеет форму данных XML. Обычно он встроен как ресурс в EXE или DLL, хотя Windows альтернативно будет искать файл .manifest родственный EXE, при запуске.
Давайте посмотрим на репрезентативный пример манифеста. Следующий манифест найден как ресурс в notepad.exe Windows 10 22H2 19045.2251 x64:
Код:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="Microsoft.Windows.Shell.notepad"
processorArchitecture="amd64"
version="5.1.0.0"
type="win32"/>
<description>Windows Shell</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:dpiAwareness>PerMonitorV2</ws2:dpiAwareness>
</windowsSettings>
</application>
</assembly>
Этот манифест определяет контекст активации, который будет активирован при запуске notepad.exe. Обратите внимание на <dependency> элемент. Он объявляет, что указанная версия сборки ( Microsoft.Windows.Common-Controls, версия 6.0.0.0) должна быть включена. Это можно найти в C:\Windows\WinSxS. После проверки Windows обнаружит приемлемое совпадение, имея собственный манифест по адресу C:\Windows\WinSxS\Manifests\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e.manifest:
Код:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" copyright="Copyright (c) Microsoft Corporation. All Rights Reserved." xmlns:cmiv2="urn:schemas-microsoft-com:asm.v3" cmiv2:copyright="Copyright (c) Microsoft Corporation. All Rights Reserved.">
<noInheritable />
<assemblyIdentity name="Microsoft.Windows.Common-Controls" version="6.0.19041.1110" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" type="win32" />
<file name="comctl32.dll" cmiv2:importPath="$(build.nttree)\asms\60\msft\windows\common\controls" cmiv2:sourceName="">
<windowClass>ToolbarWindow32</windowClass>
<windowClass>ComboBoxEx32</windowClass>
<windowClass>msctls_trackbar32</windowClass>
<windowClass>msctls_updown32</windowClass>
<windowClass>msctls_progress32</windowClass>
<windowClass>msctls_hotkey32</windowClass>
<windowClass>msctls_statusbar32</windowClass>
<windowClass>SysHeader32</windowClass>
<windowClass>SysListView32</windowClass>
<windowClass>SysTreeView32</windowClass>
<windowClass>SysTabControl32</windowClass>
<windowClass>SysIPAddress32</windowClass>
<windowClass>SysPager</windowClass>
<windowClass>NativeFontCtl</windowClass>
<windowClass>Button</windowClass>
<windowClass>Static</windowClass>
<windowClass>Listbox</windowClass>
<windowClass>ScrollBar</windowClass>
<windowClass>SysLink</windowClass>
<windowClass>tooltips_class32</windowClass>
<windowClass>ButtonListBox</windowClass>
<windowClass>SysAnimate32</windowClass>
<windowClass>SysMonthCal32</windowClass>
<windowClass>SysDateTimePick32</windowClass>
<windowClass>ReBarWindow32</windowClass>
<windowClass>Edit</windowClass>
<windowClass>Combobox</windowClass>
<windowClass>ComboLBox</windowClass>
<windowClass>DropDown</windowClass>
<signatureInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<signatureDescriptor PETrust="true" pageHash="true" />
</signatureInfo>
<asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>iXKqUejv96Ddh9vG1w798vL5l6Ox+DrmzOqVtWULo24=</dsig:DigestValue>
</asmv2:hash>
</file>
<dependency optional="yes" cmiv2:discoverable="no">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Windows.Common-Controls.Resources" version="6.0.0.0" processorArchitecture="amd64" language="*" publicKeyToken="6595b64144ccf1df" type="win32" />
</dependentAssembly>
</dependency>
<memberships xmlns:cmiv2="urn:schemas-microsoft-com:asm.v3">
<categoryMembership>
<id name="Microsoft.Windows.Categories" version="1.0.0.0" publicKeyToken="365143bb27e7ac8b" typeName="BootRecovery" />
</categoryMembership>
</memberships>
</assembly>
Элемент <file name="comctl32.dll" указывает, что файл с таким именем является частью сборки Microsoft.Windows.Common-Controls.Windows найдет его в соответствующем месте C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e\comctl32.dll. (Обратите внимание, что WinSxS это специальная папка с уникальной структурой.)
В целом, эти манифесты устанавливают контекст активации для notepad.exe, так что при notepad.exe загрузке comctl32.dll(через компоновку или явный вызов ) будет найдена соответствующая версия .comctl32.dll
На тему контекстов активации можно еще многое обсудить. Лучший универсальный ресурс по теме, который я нашел, — это статья здесь (https://omnicognate.wordpress.com/2009/10/05/winsxs/). Детали, представленные выше, тем не менее, должны быть достаточными для наших нынешних целей.
Кэш контекста активации
Процедура обнаружения манифестов, их синтаксического анализа и проверки их зависимостей, которые сами по себе должны обрабатываться рекурсивно, довольно интенсивна как с точки зрения вычислительных шагов, так и с точки зрения доступа к диску. По этой причине Microsoft представила механизм кэширования. Естественно, чтобы кеш обеспечивал выигрыш в производительности, он должен быть способен сохраняться за пределами времени жизни одного процесса, чтобы кешированные результаты можно было повторно использовать. Вероятно, именно по этой причине создание контекста активации не происходит внутри процесса, а делегируется процессу сеанса CSRSS.EXE. В приведенном выше примере notepad.exe процесс начнется с межпроцессного вызова CSRSS.EXE для создания контекста активации. CSRSS.EXE выполняет все необходимые шаги проверки и помещает результаты в структуру контекста активации в памяти. Он передает эту структуру обратно вызывающей стороне. Когда процессу необходимо загрузить модуль, такой как comctl32.dll, он обращается к этой структуре контекста активации в памяти, чтобы правильно направить загрузку библиотеки. Помимо возврата вызывающей стороне структуры контекста активации CSRSS.EXE сохраняет копию в кэше. Кэш вступает в игру при следующем запуске notepad.exe. Затем идет вызов CSRSS.EXE для создания контекста активации , CSRSS.EXE не нужно выполнять столько шагов, чтобы исследовать манифесты на диске и анализировать их. Вместо этого он извлекает контекст активации, ранее сохраненный в кэше. Чтобы убедиться, что кэшированные данные все еще действительны, нужно только проверить, не изменилось ли время модификации файла notepad.exe (хотя я намеренно опускаю некоторые менее важные детали для простоты).
В каждой записи кэша CSRSS хранится время модификации исполняемого файла, чтобы впоследствии можно было определить, действительна ли запись кэша, как я только что объяснил. Он также хранит 128-битное значение FILE_ID_INFORMATION, сгенерированное NTFS, которое служит гарантированным уникальным идентификатором файла. Это служит для предотвращения ошибок канонизации, при которых один и тот же текстовый путь может разрешаться в два разных файла из-за изменений в символических ссылках.
Однако, как это случается слишком часто, и несмотря на вышеуказанные меры предосторожности, внедрение кэширования сопряжено с серьезными рисками.
Опасность отравления кеша
Если кэш содержит неверные данные, выполнение любого процесса, использующего эти данные, может быть скомпрометировано. Например, неверные («отравленные») данные в кэше контекста активации могут привести к загрузке произвольной библиотеки DLL в привилегированный процесс, что приведет к повышению привилегий.
Как кэш может стать отравленным? Одна из проблем с архитектурой контекстов активации заключается в том, что, CSRSS.EXE выполняя генерацию и кэширование контекста активации, она делает это в интересах клиентского (вызывающего) процесса. Какой бы контекст активации ни хотел создать клиент, задача CSRSS создать этот контекст. Я предполагаю, что именно по этой причине поддерживаемый интерфейс CSRSS является довольно разрешительным, позволяя клиентскому процессу указать точный XML-файл манифеста, который будет проанализирован. Это имеет смысл, когда CSRSS рассматривается как сервер, действующий от имени клиента. Но когда в дело вступает кэширование, такое расположение становится токсичным. Контекст активации, сгенерированный из произвольного XML-файла манифеста, предоставленного клиентом, становится полупостоянной частью функционирования системы и позже может влиять на выполнение более привилегированного процесса.
CVE-2022-22047: KNOTWEED использует отравление кэша
Это подход, который был использован кодом эксплойта, найденным в дикой природе, происходящим от хакерской группы KNOTWEED. Эксплойт создает вызов в CSRSS. Вызов запрашивает контекст активации для привилегированного исполняемого файла и указывает вредоносный манифест. В манифесте используется недокументированный XML-атрибут манифеста с именем loadFrom. Этот атрибут разрешает неограниченное перенаправление DLL в любое место на диске, включая места за пределами обычного исправления поиска (обычным путем поиска является папка исполняемого файла и его подпапки, в дополнение к общим сборкам, установленным в C:\Windows\WinSxS: )
Код:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="SomePrivilegedExecutable" processorArchitecture="amd64" version="1.0.0.0" type="win32"/>
<description>Windows Shell</description>
<file loadFrom="c:\repro\payload.dll" name="advapi32.dll"/>
</assembly>
Манифест, показанный на рис. 3, указывает, что все запросы на загрузку библиотеки advapi32.dll должны вместо этого загружать файлы c:\repro\payload.dll. После создания запрошенного контекста активации CSRSS.EXE заносит его в кеш. При последующем запуске целевого исполняемого файла CSRSS.EXE предоставляет целевому процессу кэшированный контекст активации. Таким образом, когда привилегированный процесс попытается загрузить модуль advapi32.dll, от которого он зависит, вместо этого загрузится код злоумышленника.
Для проведения этой атаки единственным условием злоумышленника является возможность записать файл payload.dll где-нибудь в файловой системе. Чтобы убедиться, что кеш будет затронут, код эксплойта может сначала заполнить CSRSS запросы на очистку всех существующих записей в кеше и завершить одним последним сообщением о создании новой зараженной записи для целевого исполняемого файла.
Обратите внимание, что злоумышленник должен выбрать цель с высокими привилегиями, но работающую в том же сеансе, что и интерактивный пользователь (обычно это сеанс 1, когда есть только один интерактивный пользователь). Это связано с тем, что на сеанс приходится один CSRSS.EXE процесс и, следовательно, один кэш контекста активации на сеанс. Общий кэш на уровне сеанса делает атаку возможной.
Microsoft исправила это как CVE-2022-22047 в июльских исправлениях 2022 года, но исправление было чрезвычайно узким. Это касалось только использования недокументированного атрибута loadFrom. После исправления код в sxs.dll!CDllRedir::ContributorCallback, который обрабатывает перенаправления DLL, указанные с помощью loadFrom, устанавливает новый определенный флаг в контексте активации, указывающий, что контекст активации содержит перенаправление DLL. При проверке этого флага CSRSSлюбой такой контекст активации теперь будет рассматриваться как некэшируемый. Логика, управляющая тем, какие контексты активации вставляются в кеш, находится в sxssrv.dll!BaseSrvSxsCreateActivationContextFromStructEx.
Однако этот участок был слишком узким. Отравление кеша контекста активации может быть выполнено другими способами, кроме использования атрибута loadFrom, как мы сейчас увидим.
CVE-2022-37989: Обход исправления для эксплойта KNOTWEED
Изучив патч для эксплойта KNOTWEED, я понял, что его использование, вероятно, не единственный способ написать вредоносный манифест, внедряющий произвольный код в целевой процесс. Действительно, я быстро обнаружил, что могу написать манифест, внедряющий код с помощью другой техники: объявить зависимую сборку, которая находится в части файловой системы, контролируемой злоумышленником:
Код:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="SomePrivilegedExecutable" processorArchitecture="amd64" version="1.0.0.0” type=”win32”/>
<description>Windows Shell</description>
<dependency cmiv2:discoverable=”no”>
<dependentAssembly>
<assemblyIdentity
name="..\..\..\..\..\..\pwn\pwn"
version="1.0.0.0"
processorArchitecture="amd64"
language="*"
publicKeyToken="6595b64144ccf1df"
type="win32"/>
</dependentAssembly>
</dependency>
</assembly>
Вредоносный манифест, показанный на рисунке 4, приводит CSRSS к загрузке второго манифеста для именованной зависимости, который он находит в месте, контролируемом злоумышленником C:\pwn\pwn.MANIFEST:
Код:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" copyright="Copyright (c) Microsoft Corporation. All Rights Reserved." xmlns:cmiv2="urn:schemas-microsoft-com:asm.v3" cmiv2:copyright="Copyright (c) Microsoft Corporation. All Rights Reserved.">
<assemblyIdentity name="..\..\..\..\..\..\pwn\pwn" version="1.0.0.0" language="en-US" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" type="win32" />
<file name="advapi32.dll">
</file>
</assembly>
Здесь advapi32.dll— имя DLL, необходимое целевому процессу. В результате комбинации этих двух манифестов при загрузке целевого процесса advapi32.dllDLL будет загружаться из места, контролируемого злоумышленником, C:\pwn\а не из законного места C:\Windows\System32\. Как и прежде, локальное повышение привилегий происходит, когда целевой процесс с высокими привилегиями запускается в рамках сеанса текущего пользователя.
Microsoft исправила этот вариант в октябре 2022 года как CVE-2022-37989. Патч был аналогичен патчу для оригинального эксплойта KNOTWEED. На этот раз основное изменение кода было в sxs.dll!CNodeFactory::XMLParser_Element_doc_assembly_dependency_dependentAssembly_assemblyIdentity, который обрабатывает assemblyIdentity подэлемент элемента dependentAssembly. После исправления код этой функции проверяет, содержит ли имя зависимости какие-либо прямые или обратные косые черты. Если это так, он устанавливает другой вновь определенный флаг, очень похожий на новый флаг, представленный в патче для CVE-2022-37989.sxssrv.dll!BaseSrvSxsCreateActivationContextFromStructEx распознает контексты активации, для которых установлен этот флаг, и не помещает их в кеш.
Сомнительно, чтобы элемент dependentAssembly содержал обход каталога. Тем не менее Microsoft решила и дальше поддерживать такое поведение, возможно, ради обратной совместимости. В качестве разумного компромисса они сделали контексты активации некэшируемыми, когда они полагаются на это поведение.
CVE-2022-37987: новый вектор отравления кэша контекста активации
Обе рассмотренные выше атаки работают путем создания сообщений для CSRSS создания настроенного вредоносного контекста активации, который отличается от законного контекста активации, который обычно создается путем чтения XML-файла манифеста с диска. Удивительно, что CSRSS был спроектирован так, чтобы принимать такие конфиденциальные данные от ненадежных клиентов. Как я упоминал ранее, это можно рассматривать как разумный дизайн, если вы рассматриваете CSRSS просто как предоставление услуги клиенту. С этой точки зрения клиент должен иметь возможность указать любые детали контекста активации, которые он пожелает. Проблема возникает из-за кэширования: созданные данные из ненадежного процесса могут повлиять не только на этого клиента, но и на других клиентов, которые обращаются к CSRSS впоследствии.
Однако, как это бывает, существует совершенно отдельный вектор для внедрения произвольных данных контекста активации в CSRSS, который не имеет никакого отношения к раскрываемому интерфейсу CSRSS.
Проблема возникает из-за того, что многие обращения к своей файловой системе CSRSS.EXE выполняются, выдавая себя за вызывающего. Я считаю, что это неизбежно, потому что CSRSS необходимо создать точный контекст активации на основе того, как вызывающая сторона будет просматривать файловую систему.
Что, однако, не так широко признано, так это то, насколько сильно может выглядеть файловая система при работе под олицетворением. В частности: непривилегированный процесс может перенаправить устройство DOS, создав символическую ссылку пространства имен объектов. Например, если процесс создает символическую ссылку from \??\C:to \GLOBAL??\C:\evil, то все обращения к файловой системе с корнем C:\ вместо этого перенаправляются в корень C:\evil. Перенаправление не ограничивается процессом, который создает символическую ссылку. Скорее, это влияет на весь сеанс входа в систему. (Понятие «сеанс входа» не связано с понятием сеансов Windows. См. здесь (https://learn.microsoft.com/en-us/w...s/kernel/local-and-global-ms-dos-device-names) и здесь (https://learn.microsoft.com/en-us/windows/win32/secauthn/lsa-logon-sessions) для объяснения сеансов входа в систему.) Не только это, но и если процесс с более высоким уровнем привилегий олицетворяет токен, для которого активна символическая ссылка, привилегированный процесс также видит фиктивную файловую систему. Это верно, даже если привилегированный процесс находится в другом сеансе Windows, например, сеансе 0.
Если это пугает вас, так и должно быть. Джеймс Форшоу еще в 2015 году обнаружил, что это создает огромную дыру в безопасности - (https://bugs.chromium.org/p/project-zero/issues/detail?id=240). Каждый раз, когда привилегированный процесс олицетворяет пользователя, и привилегированный процесс загружает библиотеку (или на него можно повлиять, чтобы загрузить библиотеку) во время выполнения этого олицетворения, этот привилегированный процесс может быть полностью скомпрометирован. Все, что нужно сделать злоумышленнику, — это перенаправить C:\ в поддельное место, где привилегированный процесс подберет вредоносную версию запрошенной библиотеки.
Чтобы исправить эту дыру в безопасности, Microsoft была вынуждена добавить новый флаг атрибута объекта, распознаваемый NtOpenFile(и аналогичными API), предписывающий ядру игнорировать любые перенаправления устройств DOS, исходящие из токена олицетворения. В конце концов, Microsoft публично задокументировала этот флаг как OBJ_IGNORE_IMPERSONATED_DEVICEMAP. Вы можете найти его использование в коде загрузчика в этой выдержке из ntdll!LdrpMapDllNtFileName( ntdll.dll10.0.19041.2130, уровень патча от октября 2022 г.):
Код:
attributes = OBJ_CASE_INSENSITIVE;
ObjectAttributes.Length = 48;
if ( !LdrpUseImpersonatedDeviceMap ) // Note how Microsoft left legacy
// vulnerable behavior available
// via configuration
attributes = OBJ_IGNORE_IMPERSONATED_DEVICEMAP|OBJ_CASE_INSENSITIVE;
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.Attributes = attributes;
ObjectAttributes.ObjectName = a2;
*(_OWORD *)&ObjectAttributes.SecurityDescriptor = 0i64;
...
ntStatus = NtOpenFile(
&FileHandle,
SYNCHRONIZE|FILE_TRAVERSE|FILE_LIST_DIRECTORY,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_DELETE|FILE_SHARE_READ,
FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT);
Напротив, CSRSS до уровня исправления от декабря 2022 года этот флаг все еще не использовался OBJ_IGNORE_IMPERSONATED_DEVICEMAP. Таким образом, те операции с файловой системой CSRSS, которые выполняются под олицетворением, по-прежнему уязвимы для манипуляций со стороны злоумышленника, который устанавливает перенаправление устройства DOS.
Мы можем использовать это поведение, установив перенаправление для устройства C:\ во время выполнения операций зондирования. Перенаправление приведет CSRSS к фиктивной папке C:\Windows\WinSxS\, где мы можем разместить созданные манифесты. CSRSS будет кэшировать контекст активации, созданный из созданного манифеста, после чего локальная эскалация привилегий может продолжаться так же, как и в других атаках, описанных выше.
Например, предположим, что мы создали поддельный корень в C:\ActCtX\. (Название ActCtX произвольное) Внутри C:\ActCtX мы можем поместить фальшивую папку Windows\WinSxS, содержащую созданную копию параллельной сборки Microsoft.Windows.GdiPlus. Вредоносная копия идентична оригиналу, за исключением добавления одной зависимости в манифест:
Код:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" copyright="Copyright (c) Microsoft Corporation. All Rights Reserved." xmlns:cmiv2="urn:schemas-microsoft-com:asm.v3" cmiv2:copyright="Copyright (c) Microsoft Corporation. All Rights Reserved.">
<assemblyIdentity name="Microsoft.Windows.GdiPlus" version="1.1.19041.1706" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" type="win32" />
<dependency cmiv2:discoverable="no">
<dependentAssembly>
<assemblyIdentity name="..\..\..\..\..\..\ActCtX\ActCtX" version="1.0.0.0" processorArchitecture="amd64" language="*" publicKeyToken="6595b64144ccf1df" type="win32" />
</dependentAssembly>
</dependency>
...
Это заставляет CSRSS думать, что Microsoft.Windows.GdiPlus имеет зависимость от сборки с именем ActCtX, расположенной в корне файловой системы. Поскольку он будет искать эту сборку, нам нужно поместить ее туда:
Код:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" copyright="Copyright (c) Microsoft Corporation. All Rights Reserved." xmlns:cmiv2="urn:schemas-microsoft-com:asm.v3" cmiv2:copyright="Copyright (c) Microsoft Corporation. All Rights Reserved.">
<assemblyIdentity name="..\..\..\..\..\..\ActCtX\ActCtX" version="1.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" type="win32" />
<file name="advapi32.dll">
</file>
</assembly>
Обратите внимание, что мы перетаскиваем этот манифест в папку C:\ActCtX\ActCtX\ActCtX.MANIFEST с дополнительной папкой, указанной ActCtXв пути. Это компенсирует тот факт, что CSRSS будет обращаться к этому манифесту, пока действует перенаправление устройства DOS. Спасибо Оливеру Ляку (@ly4k_) за проработку деталей необходимой структуры папок.
Общий эффект этих манифестов заключается в том, что создается контекст активации, указывающий, что любая загрузка advapi32.dll должна быть загружена из местоположения, контролируемого злоумышленником C:\ActCtX\advapi32.dll. CSRSS будет кэшировать этот контекст активации. Когда кэшированный контекст активации повторно используется для привилегированного процесса в том же сеансе, загрузка DLL advapi32.dll вместо этого загрузит код злоумышленника в процесс, тем самым достигнув повышения привилегий до NT AUTHORITY\SYSTEM.
Microsoft исправила это в октябре 2022 года как CVE-2022-37987. Патч состоит из изменений в sxssrv.dll!BaseSrvSxsCreateActivationContextFromMessage. В этой функции код извлекает FILE_ID_INFORMATION файл EXE или DLL, для которого создается контекст активации CSRSS. Это значение становится частью ключа кэша. Ранее мы упоминали, почему это важная мера предосторожности, позволяющая гарантировать, что контекст активации, созданный для одного исполняемого файла, не будет впоследствии извлечен из кэша и применен к другому исполняемому файлу. До исправления NtQueryInformationFile операция извлечения значения FILE_ID_INFORMATION не выполнялась под олицетворением. Следовательно, когда злоумышленник создает запись в кэше, например, для C:\Windows\System32\SomePrivilegedExecutable.exe даже если злоумышленник перенаправляется с C:\ C:\evil, результирующая запись в кэше будет применяться к законному C:\Windows\System32\SomePrivilegedExecutable.exe в отличие от C:\evil\Windows\System32\SomePrivilegedExecutable.exe. Последний был бы бесполезен для злоумышленника, потому что C:\evil\Windows\System32\SomePrivilegedExecutable.exe это не исполняемый файл, который когда-либо будет запущен как привилегированный процесс. Патч Microsoft должен был добавить олицетворение во время вызова для получения файла FILE_ID_INFORMATION. Намерение этого изменения, по-видимому, заключалось в том, чтобы любой контекст активации, сгенерированный во время перенаправления DOS-устройства, применялся только к поддельному файлу и никогда к легитимному.
Как только я изучил этот патч, я весьма скептически отнесся к его эффективности, и после дальнейшего анализа и экспериментов я пришел к выводу, что мой скептицизм оправдан. К сожалению, патч ничего не дает. Злоумышленник может обойти его, просто удалив перенаправление устройств DOS на время операции NtQueryInformationFileи вернув перенаправление устройств DOS сразу же после этого. С помощью этой корректировки все можно заставить снова работать точно так же, как это работало до патча. Кроме того, я обнаружил, что злоумышленник может надежно определить точное время для отмены и восстановления перенаправления с помощью oplock.
Тем не менее причин для паники нет. Во-первых, следует отметить, что в декабре 2022 года Microsoft дополнила свой патч для CVE-2022-37987, добавив флаг использования OBJ_IGNORE_IMPERSONATED_DEVICEMAP во время проверки манифеста. Более того, хотя оригинальный патч для CVE-2022-37987 можно было легко обойти, это не обязательно означало, что атаку можно было снова запустить. Причина в том, что показанная здесь атака основана на обходе каталога внутри элемента dependentAssembly, и этот метод был эффективно заблокирован патчем для CVE-2022-37989, который обсуждался ранее. Вместо этого вы можете запросить перенаправление DLL с помощью атрибут loadFrom, но тогда вы будете аналогичным образом заблокированы патчем CVE-2022-22047. Можно попробовать и другие функции манифеста, но на данный момент я не вижу очевидных путей к выполнению произвольного кода. Можно указать перенаправление COM-класса через элемент comClass, чтобы вызвать непредвиденную загрузку DLL в привилегированный процесс, но это будет ограничено DLL, уже существующими в безопасном месте (например, System32). Это может привести к сбою в привилегированном процессе, но эксплуатация для выполнения произвольного кода остается чрезвычайно сложной. Определение того, остаются ли какие-либо потенциально опасные функции файлов манифеста неисправленными, является интересным открытым исследовательским вопросом.
Существует еще одна причина, по которой угроза локального повышения привилегий с использованием отравления кэша контекста активации теперь значительно снижена: Microsoft ввела общую защиту.
Снижение угрозы отравления кэша контекста активации
В дополнение к конкретным исправлениям от июля 2022 г., октябрю и декабрю 2022 г., описанным выше, в октябре 2022 г. Microsoft мудро добавила общее средство защиты.
Начиная с патча от октября 2022 года, значение уровня целостности теперь хранится вместе с каждой записью кэша. Например, обычный непривилегированный процесс, работающий в рамках интерактивного сеанса, имеет уровень целостности Medium (десятичное число 8192, шестнадцатеричное число 0x2000). Если этот процесс вызывает CSRSS для создания контекста активации и CSRSS создает новую соответствующую запись кэша, запись кэша будет помечена 0x2000 (средний) в качестве уровня целостности. Впоследствии, если другой процесс, работающий со средней или более низкой целостностью, вызывается CSRSS для создания контекста активации для того же исполняемого файла, CSRSS удовлетворит запрос из кэша. Напротив, если процесс, работающий с уровнем целостности выше среднего, делает такой запрос, CSRSS будет рассматривать его как промах кэша. В этом случае CSRSS создаст контекст активации с нуля и удалит существующую запись кэша, заменив ее новой, имеющей более высокую метку целостности. Эта логика содержится в sxssrv!BaseSrvSxsCreateActivationContextFromStructEx.
Эта защита очень полезна. Это чрезвычайно сокращает диапазон сценариев, в которых кеш может быть средством повышения привилегий. Например, в атаке KNOTWORM и во всех вариантах, описанных выше, процесс, запущенный как Medium, создает вредоносную запись в кэше, которая позже будет обнаружена процессом, работающим в NT AUTHORITY\SYSTEM сеансе пользователя. Насколько мне известно, при стандартной установке Windows все процессы, запускаемые в рамках NT AUTHORITY\SYSTEM интерактивного сеанса, имеют уровень целостности System (десятичное число 16384, шестнадцатеричное число 0x4000). Таким образом, благодаря этой защите, когда придет время для извлечения записи кэша для использования привилегированным процессом, запись CSRSS с более низкой целостностью будет отброшена, так что привилегированный процесс останется полностью незатронутым ею.
Эта защита не является панацеей. Отравление кеша контекста активации остается жизнеспособным методом атаки, но только в очень ограниченном наборе обстоятельств. Напомним, что на сеанс приходится один процесс CSRSS.EXE, поэтому по своей природе кеш является сеансовым. Добавьте к этому ограничение, налагаемое мерой, заключающееся в том, что запись кэша, созданная процессом с более низким уровнем целостности, никогда не будет подхвачена процессом с более высоким уровнем целостности. Остается небольшое подмножество сценариев повышения привилегий, которые обходят эти ограничения. Я приведу два примера:
• Процесс службы Dnscache (также известный как «DNS-клиент») работает как NETWORK SERVICE, но SeImpersonatePrivilege удален из своего токена. Технически это делает Dnscache процесс с низким уровнем привилегий. Если злоумышленник скомпрометирует этот процесс, обычно не так просто перейти к NT AUTHORITY\SYSTEM. Тем не менее, поскольку процесс выполняется с целостностью системы (не путать с NT AUTHORITY\SYSTEM), а его сеанс является сеансом 0, вредоносный код, работающий внутри, Dnscache может отравить кэш контекста активации, чтобы скомпрометировать любую службу, работающую в сеансе 0, как NT AUTHORITY\SYSTEM. Обратите внимание, однако, что для завершения повышения привилегий также необходимо найти неисправленную функцию манифеста, как обсуждалось ранее.
• dwm.exe - это процесс, который выполняется в каждом интерактивном сеансе. Он работает как интерактивный пользователь, но с целостностью системы. Таким образом, злоумышленник, выполнивший код, сможет создать запись в кэше с уровнем целостности системы, которая будет подхвачена процессами с высоким уровнем привилегий, которые также выполняются в рамках интерактивного сеанса, как и в исходной атаке KNOTWEED. Примечательно, что был отчет о вероятной компрометации, dwm.exe используемой цепочкой эксплойтов в дикой природе, хотя, поскольку этот отчет предшествует защите кэша, злоумышленник в этом случае должен был преследовать другую цель при компрометации dwm.exe. Опять же, чтобы завершить повышение привилегий, необходимо найти неисправленную функцию манифеста.
Заключение
Мы раскрыли новый класс ошибок в Microsoft Windows, который мы называем отравлением кэша контекста активации. Успешная эксплуатация обычно приводит к повышению привилегий, как это достигается в дикой природе группой KNOTWEED. Все уязвимости, недавно обнаруженные как уязвимости «CSRSS», попадают в этот новый класс ошибок. Хотя корпорация Майкрософт уже выпустила общее средство защиты, остаются краеугольные случаи, выходящие за рамки меры защиты. Остается открытым исследовательский вопрос, достаточно ли специальных исправлений Microsoft для известных уязвимостей, чтобы обеспечить безопасное кэширование контекстов активации между процессами.