Локальная картошка. Исследуем уязвимость в локальной аутентификации Windows
В этой статье речь пойдет об уязвимости, позволяющей выполнить локальное повышение привилегий (LPE) в операционных системах семейства Windows. Баг напрямую связан с NTLM-аутентификацией, поэтому сначала поговорим о том, как она устроена, а потом перейдем непосредственно к разбору CVE-2023-21746.
NTLM-АУТЕНТИФИКАЦИЯ
Предположим, пользователь хочет получить доступ к файловому ресурсу на другом компьютере или сервере. Аутентификация выполняется в четыре этапа:
- Пользователь отправляет серверу запрос с именем учетной записи.
- В ответ сервер отправляет ему случайное число, называемое challenge.
- Пользователь шифрует это число своим NT-хешем и отправляет обратно.
- Сервер извлекает из SAM (Security Account Manager — RPC-сервер Windows, оперирующий базой данных учетных записей) хеш пользователя и проделывает те же самые действия, что и пользователь, сравнивая полученные хеши. Если результаты совпали, то аутентификация считается успешной.
ЛОКАЛЬНАЯ АУТЕНТИФИКАЦИЯ NTLM
Рассмотрим локальную аутентификацию NTLM, которая начинается с аутентификации пользователя на самой машине.
Эта аутентификация выполняется следующим образом:
- Пользователь вводит свои учетные данные, логин и пароль, при входе на машину.
- Введенные данные передаются подсистеме локальной безопасности LSA, которая преобразует пароль в хеш.
- Далее LSA передает имя пользователя SAM, который извлекает хеш указанного пользователя.
- LSA сверяет хеши, и если они совпадают, то пользователь получает доступ к машине.
Далее срабатывает рассмотренный выше механизм, основанный на модели клиент — сервер.
Локальная аутентификация NTLM — это частный случай, она применяется, когда клиентская и серверная части работают на одной машине.
Клиент получает учетные данные вошедшего в систему пользователя и создает запрос, содержащий имя рабочей станции и домена клиента.
Сообщение типа 1. Клиент посылает это сообщение для начала соединения. Оно используется для согласования параметров аутентификации, как и раньше, но также содержит имя клиентской машины и ее домен. Сервер может проверить имя и домен клиента, и, если они совпадают с его собственными, начинается процесс локальной аутентификации.
Сообщение типа 2. Сервер создает контекст безопасности, вызывая функцию AcceptSecurityContext (NTLM), и в этом сообщении отправляет клиенту его идентификатор. Затем клиент может использовать идентификатор контекста безопасности, чтобы связать себя с соединением.
Сообщение 3-го типа. Клиент получает токен и передает его в InitializeSecurityContext (NTLM). Если InitializeSecurityContext (NTLM) возвращает SEC_E_OK, то взаимная аутентификация завершена и можно начинать защищенный сеанс. Если же он возвращает код ошибки, то переговоры о взаимной аутентификации завершаются. В противном случае токен безопасности, возвращенный InitializeSecurityContext (NTLM), отправляется клиенту и шаги 2 и 3 повторяются.
КАК РАБОТАЕТ LOCALPOTATO
LocalPotato использует недостаток в механизме локальной аутентификации NTLM. Эксплоит обманывает привилегированный процесс и заставляет аутентифицировать сеанс, запущенный хакером. В результате атакующий получает соединение, предоставляющее ему доступ к любым ресурсам с привилегиями обманутого процесса.
«Картошка» работает следующим образом:
- Хакер запускает привилегированный процесс для подключения к подконтрольному ему серверу. В принципе, это работает аналогично предыдущим Potato, когда непривилегированный пользователь заставлял ОС создавать соединения, использующие права SYSTEM.
- Сервер на машине создаст контекст безопасности А для привилегированного соединения, но не будет отправлять его сразу. Хакер запустит свой клиент, чтобы он одновременно с локальным инициировал соединение с сервером. Легитимный клиент отправляет сообщение, чтобы инициировать соединение, а сервер в ответ пошлет сообщение с идентификатором нового контекста безопасности Б.
- Злоумышленник также запускает свой сервер и меняет идентификаторы контекстов обоих соединений таким образом, чтобы привилегированный процесс получил контекст соединения с сервером злоумышленника, а не со своим собственным. В результате хакер сможет получить доступ к любому сетевому ресурсу с привилегиями SYSTEM.
STORSVC И DLL HIJACKING
До сих пор мы использовали LocalPotato для записи любых файлов на целевую машину. Чтобы получить привилегированную оболочку, нам нужно выяснить, как использовать произвольную запись для выполнения команды.
Недавно был обнаружен еще один вектор повышения привилегий, когда злоумышленник мог перехватить отсутствующую DLL для выполнения произвольных команд с привилегиями SYSTEM. Единственная проблема этого вектора заключалась в том, что для его запуска злоумышленнику необходимо было записать DLL в системную переменную PATH. По умолчанию в PATH Windows включаются только те каталоги, в которые могут писать лишь привилегированные учетные записи. Хотя можно найти машины, на которых установка определенных приложений изменила переменную PATH и сделала машину уязвимой, вектор атаки применим только к конкретным сценариям. Комбинирование данной атаки с LocalPotato позволяет преодолеть это ограничение и получить полностью рабочий эксплоит для повышения привилегий.
Как выяснила компания BlackArrow, злоумышленник может отправить RPC-вызов методу SvcRebootToFlashingMode, предоставляемому службой StorSvc, что, в свою очередь, приведет к попытке загрузки отсутствующей DLL под названием SprintCSP.dll.
Если ты незнаком с RPC, то считай, что это API, который раскрывает функции для удаленного использования. В описанном случае служба StorSvc раскрывает метод SvcRebootToFlashingMode, который может вызвать любой человек, имеющий доступ к машине.
Поскольку StorSvc работает с привилегиями SYSTEM, создание SprintCSP.dll где‑нибудь в PATH приведет к загрузке библиотеки при каждом вызове SvcRebootToFlashingMode.
КОМПИЛЯЦИЯ ЭКСПЛОИТА
Теперь, когда мы знаем всю теоретическую базу, мы можем приступить к выполнению практической части. Все необходимое для дальнейших действий можно найти в репозитории на GitHub.
Чтобы воспользоваться эксплоитом CVE-2023-21746, сначала надо скомпилировать два файла:
SprintCSP.dll. Это недостающая DLL, которую мы собираемся перехватить. Код по умолчанию, поставляемый с эксплоитом, выполняет командуwhoamiи выводит ответ вC:\Program Data\whoamiall.txt. Нам нужно изменить команду, чтобы достигнуть нашей цели;RpcClient.exe. Эта программа запустит RPC-вызовSvcRebootToFlashingMode. В зависимости от версии Windows, на которую нацелен эксплоит, его код может потребоваться немного подправить, поскольку в разных версиях Windows используются разные идентификаторы интерфейсов для раскрытияSvcRebootToFlashingMode.
Для начала разберемся с файлом RpcClient.exe. Как уже говорилось, нам потребуется изменить эксплоит в зависимости от версии Windows на целевой машине. Для этого нужно отредактировать первые строки файла C:\tools\LPE via StorSvc\RpcClient\RpcClient\storsvc_c.c так, чтобы выбиралась нужная операционная система. Поскольку моя машина работает под управлением Windows Server 2019, я отредактирую файл следующим образом.
Это настроит эксплоит на использование корректного идентификатора интерфейса RPC для моей версии Windows. Теперь, когда код исправлен, скомпилируем необходимые нам инструменты.
Перед компиляцией SprintCSP.dll нам нужно изменить функцию DoStuff() в файле SprintCSP\main.c таким образом, чтобы она добавляла нашего текущего пользователя в группу Administrators. Вот код с нашей замененной командой:
void DoStuff() {
// Replace all this code by your payload STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi; CreateProcess(L"c:\\windows\\system32\\cmd.exe",L" /C net localgroup administrators user /add", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, L"C:\\Windows", &si, &pi); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return;}
Теперь скомпилируем нашу DLL.
ЭКСПЛУАТАЦИЯ
Для начала удостоверимся, что наш пользователь действительно не входит в группу локальных администраторов.
Для успешной эксплуатации StorSvc необходимо скопировать SprintCSP.dll в любую директорию текущей PATH. Проверить PATH можно, выполнив следующую команду:
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" -v Path
Мы будем использовать каталог %SystemRoot%\system32, который расширяется до C:\windows\system32. Однако ты можешь использовать любой из этих двух каталогов.
Теперь, когда все готово, можем запустить LocalPotato:
LocalPotato.exe -i SprintCSP.dll -o \Windows\System32\SprintCSP.dll
DLL успешно записалась в System32! Теперь мы можем запустить RpcClient.exe для запуска вызова SvcRebootToFlashingMode, выполнив полезную нагрузку в нашей DLL.
Чтобы удостовериться, что эксплоит сработал, проверим, находится ли наш пользователь в группе администраторов.
ВЫВОД
После успешного срабатывания эксплоита мы можем выполнить любые действия от лица администратора под учетной записью пользователя user. Например, запустить командную строку.
Оптимальная защита от эксплуатации этой уязвимости (как и других подобных) — своевременно устанавливать обновления безопасности Microsoft. Тем не менее даже в этом случае некоторые протоколы, использующие NTLM в качестве метода аутентификации, могут быть уязвимы для подобных атак.