Skip to main content

Command Palette

Search for a command to run...

LocalPotato Windows LPE CVE-2023-21746

Updated
8 min read
LocalPotato Windows LPE CVE-2023-21746
S

Professional pentester, technical writer, telegram channel owner

Интро

Путь к обнаружению LocalPotato начался с подсказки Элада Шамира, который предложил изучить поле "Reserved" в сообщениях NTLM Challenge на предмет потенциальных возможностей эксплуатации.

После обширного исследования он пришел к "LocalPotato", не очень распространенной атаке отражения NTLM в локальной аутентификации, позволяющей произвольное чтение/запись файлов. Сочетание возможности произвольной записи в файл с выполнением кода позволило нам добиться повышения привилегий по всей цепочке от пользователя до SYSTEM.

Мы сообщили о наших находках в Microsoft Security Response Center (MSRC) 9 сентября 2022 года, и они были устранены с выпуском январского вторника исправлений 2023 года и получили номер CVE CVE-2023-21746.

Local NTLM Authentication

Механизм аутентификации NTLM является частью NTLMSSP (NTLM Security Support Provider), который поддерживается структурой безопасности Windows под названием SSPI (Security Support Provider Interface). SSPI предоставляет гибкий API для работы с токенами аутентификации и поддерживает несколько базовых провайдеров, включая NTLMSSP, SPNEGO, Kerberos и т.д..

Процесс аутентификации NTLM включает обмен тремя типами сообщений (тип 1, тип 2 и тип 3) между клиентом и сервером, которые обрабатываются NTLMSSP. Квитирование аутентификации SSPI абстрагируется от деталей NTLM и позволяет использовать независимые от конкретного механизма, средства для применения принципов аутентификации, целостности и конфиденциальности.

Local authentication - это особый случай NTLM-аутентификации, при котором клиент и сервер находятся на одной машине. Клиент получает учетные данные вошедшего в систему пользователя и создает сообщение типа 1, которое содержит рабочую станцию и доменное имя клиента. Сервер проверяет информацию о домене и рабочей станции и инициирует локальную аутентификацию, если они совпадают. Затем клиент получает от сервера сообщение типа 2 и проверяет наличие флага "Negotiate Local Call", чтобы определить, действителен ли дескриптор контекста безопасности. Если это так, то учетные данные по умолчанию ассоциируются с контекстом сервера, и итоговое сообщение типа 3 становится пустым. Затем сервер проверяет, связан ли контекст безопасности с пользователем, и если да, то аутентификация завершается.

В общем, во время локальной аутентификации поле "Reserved", которое обычно устанавливается в ноль для нелокальной аутентификации в сообщении NTLM типа 2, будет ссылаться на дескриптор контекста локального сервера, с которым должен ассоциироваться клиент.

В общем, во время локальной аутентификации поле "Reserved", которое обычно устанавливается в ноль для нелокальной аутентификации в сообщении NTLM типа 2, будет ссылаться на дескриптор контекста локального сервера, к которому должен подключиться клиент.

На рисунке выше мы выделили поле Reserved, содержащее верхнее значение контекстного дескриптора.

Логический баг

Аутентификацию NTLM через SPPI часто неправильно понимают как прямую взаимную аутентификацию между клиентом и сервером. Однако на самом деле локальный аутентификатор (LSASS) всегда участвует в процессе, выступая в качестве посредника между ними. Он отвечает за создание сообщений, проверку разрешений на идентификацию и генерирование соответствующих маркеров.

Целью нашего исследования было перехватить локальную NTLM-аутентификацию непривилегированного локального или доменного пользователя и "подменить" контекст (поле NTLM "Reserved") на контекст привилегированного пользователя (например, путем принуждения к аутентификации).

Это позволит нам пройти аутентификацию в службе сервера с этими учетными данными, эффективно обменяв личность нашего низкопривилегированного пользователя на более привилегированную сущность, такую как SYSTEM. В случае успеха это указывает на отсутствие проверок для подтверждения подлинности Контекста, которым обмениваются две стороны, участвующие в аутентификации.

Процесс атаки выглядит следующим образом:

  1. Принудительная аутентификация привилегированного пользователя на нашем сервере.

  2. Инициируем NTLM-аутентификацию нашего клиента на службе сервера.

  3. Перехват контекста "B" (Зарезервированные байты) сообщения NTLM Type 2, исходящего от службы сервера, где наш непривилегированный клиент пытается пройти аутентификацию.

  4. Получение контекста "A" (Зарезервированные байты) сообщения NTLM Type 2, созданного нашим сервером, когда привилегированный клиент пытается аутентифицироваться.

  5. Поменяйте контекст A на B, чтобы привилегированный клиент аутентифицировался в службе сервера от имени непривилегированного клиента и наоборот.

  6. Получите оба пустых ответных сообщения NTLM Type 3 и перешлите их в правильном порядке, чтобы завершить оба процесса аутентификации.

  7. В результате обмена контекстами подсистема локальных органов безопасности (LSASS) свяжет контекст B с привилегированной идентификацией, а контекст A - с непривилегированной.

  8. Это приводит к подмене контекстов, позволяя нашему вредоносному клиенту пройти аутентификацию от имени привилегированного пользователя.

Ниже приведено графическое представление потока атаки:

Для подтверждения наших предположений об атаке подмены контекста мы разработали специальный сценарий. В нашем эксперименте мы использовали два сокет-сервера и два сокет-клиента для аутентификации через NTLM с разными пользователями и обмена "контекстом" друг друга. Обе стороны согласовывали аутентификацию NTLM через сокет посредством SSPI. В частности, клиенты с помощью двух вызовов InitializeSecurityContext(), а серверы с помощью двух вызовов AcceptSecurityContext().

После некоторых корректировок мы успешно поменялись идентификаторами и смогли обмануть LSASS, связав контекст с "неправильным" сервером.

Чтобы использовать это в реальном сценарии, нам нужно было найти полезный триггер для принуждения привилегированного клиента и соответствующей службы сервера.

Триггеры для принудительного использования привилегированного пользователя

На основе наших предыдущих исследований мы определили два ключевых триггера для принуждения привилегированного клиента: попытка службы BITS аутентифицироваться как пользователь SYSTEM через HTTP на порту 5985 (WinRM) и аутентифицированные вызовы привилегированных пользователей RPC/DCOM.

RogueWinRM - это техника, которая использует попытку службы BITS аутентифицироваться как пользователь SYSTEM через HTTP на порту 5985. Поскольку этот порт не включен по умолчанию в Windows 10/11, это дает возможность реализовать собственный HTTP-сервер, который может перехватить поток аутентификации. Это позволяет нам получить аутентификацию на уровне SYSTEM.

RemotePotato0 - это метод принудительной привилегированной аутентификации на целевой машине, использующий преимущества стандартного COM marshaling. В нашем сценарии мы обнаружили три интересных CLSID по умолчанию, которые аутентифицируются как SYSTEM:

  1. CLSID: {90F18417-F0F1-484E-9D3C-59DCEEE5DBD8}
    The ActiveX Installer Service "AxInstSv" is available only on Windows 10/11.

  2. CLSID: {854A20FB-2D44-457D-992F-EF13785D2B51}
    The Printer Extensions and Notifications Service "PrintNotify" is available on Windows 10/11 and Server 2016/2019/2022.

  3. CLSID: {A9819296-E5B3-4E67-8226-5E72CE9E1FB7}
    The Universal Print Management Service "McpManagementService" is available on Windows 11 and Server 2022.

Используя один из этих триггеров, мы можем получить соответствующую привилегированную идентификацию для взлома.

Взлом службы сервера

Первоначально мы попытались найти привилегированного кандидата для нашей службы сервера, изучив открытые службы RPC, такие как диспетчер управления службами. Однако мы столкнулись с проблемой локальной аутентификации для служб RPC, поскольку невозможно выполнить атаки отражения или ретрансляции из-за ограничений в библиотеке времени выполнения RPC (rpcrt4.dll).

Как объясняется в этом сообщении блога Джеймса Форшоу, компания Microsoft добавила защиту в среду выполнения RPC для предотвращения успешных атак ретрансляции аутентификации. Это делается в "SSECURITY_CONTEXT::ValidateUpgradeCriteria()" путем проверки, была ли аутентификация для RPC-соединения из локальной системы, и если да, то устанавливается флаг в контексте безопасности. Сервер отклоняет вызов RPC, если этот флаг установлен, до того, как будет вызван какой-либо код на сервере. Единственный способ обойти эту проверку - это либо аутентификация от нелокальной системы, либо уровень аутентификации RPC_C_AUTHN_LEVEL_PKT_INTEGRITY или выше, что требует знания ключа сессии для подписания или шифрования, что, конечно, эффективно предотвращает любые попытки ретрансляции.

Далее мы обратили внимание на SMB-сервер с целью выполнения произвольной записи файла с повышенными привилегиями.

Единственным требованием было то, что SMB-сервер не должен требовать подписи, что является стандартным для серверов, не являющихся контроллерами домена.

Однако мы обнаружили, что протокол SMB также имеет некоторые меры по предотвращению кросс-протокольных атак на отражение.

Это исправление, также называемое CVE-2016-3225, было выпущено для устранения сценария атаки WebDAV->SMB relaying.

По сути, оно требует использования SPN "cifs/127.0.0.1" при инициализации локальной аутентификации через InitializeSecurityContext() для подключения к серверу SMB, даже для протоколов аутентификации, отличных от Kerberos, таких как NTLM.

Основная идея этого исправления заключается в предотвращении ретрансляции локальной аутентификации между двумя различными протоколами, что может привести к несоответствию SPN в аутентификаторе и, в конечном итоге, к ошибке отказа в доступе.

Согласно статье Джеймса Форшоу "Windows Exploitation Tricks: Relaying DCOM Authentication", можно обмануть привилегированного клиента DCOM, заставив его использовать произвольное имя Service Principal Name (SPN) для подделки произвольного билета Kerberos. Хотя это относится к Kerberos, оказалось, что это также может повлиять на настройку SPN в NTLM-аутентификации. По этой причине мы решили использовать триггер RPC/DCOM для принуждения привилегированного клиента, поскольку мы могли вернуть произвольный SPN в строки привязки резольвера Oxid, тем самым обойдя механизм защиты SMB от отражения. Все, что нам нужно было сделать, это установить SPN "cifs/127.0.0.1" в исходном привилегированном клиенте, что не было проблемой благодаря нашему триггеру:

В итоге мы смогли записать произвольный файл с привилегиями SYSTEM и произвольным содержимым. Сетевой захват SMB-пакетов показывает, что мы успешно аутентифицировались на ресурсе C$ как пользователь SYSTEM и перезаписали файл PrintConfig.dll:

POC

Создание POC LocalPotato было сложной задачей, поскольку требовалось написать SMB-пакеты и отправить их через интерфейс loopback для низкоуровневой NTLM-аутентификации, получить доступ к локальному ресурсу и, наконец, записать файл. Для завершения процесса мы полагались на записи Wireshark и спецификации протокола MS-SMB2 от Microsoft. После многочисленных тестов и корректировок кода мы, наконец, добились успеха.

Чтобы упростить цепочку атак, мы решили исключить перенаправление на машину не-Windows, прослушивающую порт 135, и вместо этого запустили поддельный резолвер oxid на машине жертвы Windows, чтобы триггер Potato был локальным и вся цепочка атак была полностью локальной.

Как и в JuicyPotatoNG, мы использовали хуки SPPI для манипулирования NTLM-сообщениями, приходящими на наш COM-сервер от привилегированного клиента, что позволило осуществить подмену контекста.

Преобразование записи произвольного файла в EoP относительно простое. В нашем случае мы использовали CLSID McpManagementService на сервере Windows 2022, перезаписали библиотеку printconfig.dll и инстанцировали объект PrintNotify. Это заставило службу загрузить наш вредоносный PrintConfig.dll, предоставив нам оболочку SYSTEM:

Существуют различные методы использования произвольной записи в файл для выполнения кода как SYSTEM, например, использование XPS Print Job или NetMan DLL Hijacking. Так что вы можете комбинировать LocalPotato с тем, что вам больше нравится ;)

LocalPotato POC тут → https://github.com/decoder-it/LocalPotato

Патч

Уязвимость LocalPotato была обнаружена в схеме аутентификации NTLM. Чтобы найти источник уязвимости, мы провели бинарный diff-анализ msv1_0.dll, пакета безопасности, загруженного в LSASS для обработки всех операций, связанных с NTLM:

Основное внимание при анализе было уделено функции SsprHandleChallengeMessage(), которая обрабатывает вызовы NTLM.

Мы заметили добавление новой проверки на включенную функцию "Feature_MSRC74246_Servicing_NTLM_ServiceBinding_ContextSwapping", когда происходит аутентификация:

Проверка, введенная Microsoft, гарантирует, что если установлен флаг ISC_REQ_UNVERIFIED_TARGET_NAME и присутствует SPN, то SPN устанавливается в NULL.

Это изменение эффективно устраняет уязвимость, нарушая этот конкретный сценарий эксплуатации.

Механизм защиты SMB проверяет наличие определенного SPN, например, "cifs/127.0.0.1", чтобы определить, разрешить или запретить доступ. С установленным патчем будет найдено значение NULL, что приведет к отказу в аутентификации. Важно отметить, что флаг ISC_REQ_UNVERIFIED_TARGET_NAME передается и используется привилегированным клиентом DCOM, но до этого патча он не учитывался при аутентификации NTLM.

Microsoft выпустила исправления для поддерживаемых версий Windows, но не волнуйтесь, если у вас более старая версия. 0patch предоставляет исправления для LocalPotato и для неподдерживаемых версий!

Выводы

В заключение, уязвимость LocalPotato подчеркивает слабые места алгоритма аутентификации NTLM при локальной аутентификации.

Компания Microsoft решила проблему выпуском исправления CVE-2023-21746, но это исправление может быть лишь обходным решением, поскольку обнаружение поддельных контекстных дескрипторов в протоколе NTLM может быть затруднено.

Важно отметить, что данный тип атаки не является специфическим для протоколов SMB или RPC, а скорее представляет собой общую слабость в потоке аутентификации. Другие протоколы, использующие NTLM в качестве метода аутентификации, все еще могут быть уязвимы, при условии, что будут найдены службы, пригодные для эксплуатации.

More from this blog

Инъекция XSS в скрытых полях ввода и мета-тегах

​Введение​ В этом посте автор покажет, как вы можете использовать новую функцию всплывающих окон HTML в Chrome для эксплуатации XSS в мета-тегах и скрытых полях ввода. Все началось, когда я заметил новое поведение всплывающих окон в Chrome на Twitter...

Jul 13, 20233 min read178
Инъекция XSS в скрытых полях ввода и мета-тегах

Zybnev Sergey | Pentester | Blog

19 posts

Professional pentester, programmer and web designer.