Содержание статьи
- Компоненты безопасности
- Security Package
- SSP/AP (или же просто AP)
- Security Providers
- Credential Providers
- Password Filters
- Как происходит вход пользователя в систему
- Инициализация LSA
- Эксплуатация
- Как дебажить?
- Перехват пароля с помощью внедрения Security Package
- Перехват пароля с помощью внедрения Password Filter
- Перехват пароля с помощью диспетчера учетных данных
- Выводы
Windows имеет сложную систему аутентификации со множеством компонентов. Фундаментом этой системы можно считать LSA (Local Security Authority) и SSP.
LSA — огромная подсистема, которая служит для проверки подлинности пользователей, их регистрации, смены пароля и подобных операций. Еще в LSA хранится информация обо всех аспектах безопасности локального компьютера, например количестве неуспешных вводов пароля для блокировки учетной записи. Посредством LSA можно даже назначать привилегии пользовательским учеткам, для этого разработан инструмент Privileger.
SSP тоже не так прост, как кажется: мы рассмотрели его использование в клиент‑серверных процессах в прошлой статье. Он не только помогает разработчикам шифровать данные, обеспечивать целостность передаваемой информации, выстраивать контекст, но и может расширить стандартную аутентификацию. Правда, для этой цели будет использоваться не просто SSP, а SSP/AP, о котором мы поговорим позже.
Компоненты безопасности
Их можно считать кирпичиками, из которых строится вся огромная система аутентификации в Windows. Отмечу, что теория из этой статьи будет распространяться и на последующий материал. Мы начнем с простейшего перехвата пароля, а затем будем понемногу усложнять себе задачу.
Security Package
Security Package (SP) — программная реализация некоего протокола безопасности. Security Package содержатся в SSP (и/или SSP/AP) в виде DLL-файлов. Например, Kerberos и NTLM находятся в SSP Secur32.
. Да, именно в Secur32.
, так как именно этот SSP делегирует функции безопасности нужному SP. Например, если служба требует аутентификацию по Kerberos, то Secur32.
вызовет Kerberos.
.
SSP/AP (или же просто AP)
AP — Authentication Package. Представляет собой библиотеку DLL, которая тоже содержит один или несколько SP. Главное отличие от стандартного SSP заключается в том, что SSP/AP может выступать в качестве пакета аутентификации (AP), то есть проверять подлинность введенных данных при входе пользователя в систему.
Тем не менее SSP/AP выполняет и все функции стандартного SSP (выстраивать контекст, шифровать данные и прочие). Чтобы SSP/AP мог функционировать и в качестве пакета аутентификации, и в качестве обычного SSP для клиент‑серверных процессов, при запуске системы он загружается в пространство процесса lsass.
.
Также, если требуется работать лишь с клиент‑серверными функциями конкретного SSP/AP, он без проблем может быть загружен в клиент‑серверное приложение. Например, методом динамического (функция LoadLibrary(
) либо статического связывания (pragma
), то есть без загрузки в процесс lsass.
. В таком случае функции пакета аутентификации использоваться не будут.
Security Providers
Security Providers не стоит путать с Security Package. Они все‑таки различаются.
Провайдеры безопасности реализованы в виде DLL и позволяют выполнить так называемую вторичную аутентификацию. То есть после того, как пользователь прошел аутентификацию на одной машине, он может пройти аутентификацию и на другой машине, например на сервере Linux. Таким образом, пользователь получает доступ к ресурсам UNIX-сервера с машины Windows без дополнительной аутентификации. Это называется Single Sign-On.
Credential Providers
Провайдеры учетных данных — COM-объекты, служащие для беспарольного доступа к системе. Реализованы тоже в виде динамических библиотек DLL. Например, для распознавания лица используется FaceCredentialProvider.
, для смарт‑карт — SmartcardCredentialProvider.
.
Также может использоваться сторонний поставщик учетных данных. Все доступные поставщики учетных данных перечислены здесь:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers
Каждый ключ по этому пути реестра идентифицирует определенный класс поставщика безопасности по его CLSID
. Сам CLSID
должен быть зарегистрирован в HKCR\
, так как является классом COM
. Для изучения всех доступных поставщиков также можно воспользоваться инструментом CPlist.exe.
Password Filters
С помощью Password Filters можно расширить стандартную парольную политику на конкретных хостах. Когда создается запрос на смену пароля, LSA вызывает все пакеты уведомлений, чтобы проверить, удовлетворяет ли новый пароль фильтрам, реализованным внутри пакета. Причем каждый пакет уведомлений вызывается дважды:
- Для проверки нового пароля. Если какой‑то из пакетов уведомлений сообщает, что пароль не подходит, система потребует у пользователя указать иной пароль.
- Для уведомления о том, что пароль изменился. Этот вызов произойдет только тогда, когда все пакеты уведомлений сообщили, что пароль нормальный и соответствует их фильтрам.
Password Filter можно считать частным случаем Notification Package.
Как происходит вход пользователя в систему
Перед тем как мы сможем перехватить пароль, следует разобраться с процессом входа пользователя в систему. В этой статье мы не будем вдаваться в подробности инициализации Winlogon, создания рабочих столов, GINA. Просто знай, что именно благодаря процессу Winlogon.
осуществляется интерактивный вход. Система запустилась, пользователь сел за клавиатуру.
Для начала аутентификации отправляется комбинация клавиш SAS (по умолчанию Ctrl + Alt + Del). Winlogon получает это сообщение, начинается процесс входа.
Так как в современных системах присутствует множество вариантов беспарольного входа (отпечаток пальца, распознавание лица), то Winlogon обращается к Credential Providers, чтобы получить информацию об аутентифицирующемся пользователе.
Вне зависимости от ответа провайдера учетных данных Winlogon порождает процесс
LogonUI.
. Он предоставляет интерфейс для ввода пароля и завершается после окончания этого действия. Таким образом,exe LogonUI.
может перезапускаться бесконечное количество раз, если вдруг возникают какие‑либо ошибки. Как следствие, обеспечивается защита от возможного крашаexe Winlogon.
.exe После того как пользователь ввел свой логин и пароль либо если провайдер учетных данных вернул их, Winlogon создает уникальный SID для входа этого пользователя. Данный SID назначается всему текущему экземпляру рабочего стола (клавиатура, мышь, экран). После чего идет обращение к процессу
lsass.
с целью аутентификации пользователя.exe Обращение можно разделить на несколько этапов. Сначала
Winlogon.
регистрирует себя как процесс аутентификации. Делается это вызовом функцииexe LsaRegisterLogonProcess(
. В случае успешного вызова процесс получает хендл на LSA для последующего взаимодействия. Причем взаимодействие будет осуществляться посредством ALPC (Advanced Local Procedure Calls).) -
Далее
Winlogon.
получает хендл на пакет аутентификации MSV1_0 (и Kerberos в случае AD, тут мы рассматриваем только MSV1_0) путем вызоваexe LsaLookupAuthenticationPackage(
:) NTSTATUS LsaLookupAuthenticationPackage([in] HANDLE LsaHandle,[in] PLSA_STRING PackageName,[out] PULONG AuthenticationPackage);Эта функция ничего особенного не требует.
LsaHandle
— хендл, полученный вызовомLsaRegisterLogonProcess(
;) PackageName
— имя пакета аутентификации, напримерMSV1_0_PACKAGE_NAME
;AuthenticationPackage
— полученный идентификатор желаемого для использования Winlogon пакета аутентификации. Получив идентификатор пакета аутентификации, Winlogon передает ему информацию в вызове функции
LsaLogonUser(
. Эта информация содержит SID из шага 4, а также информацию об аутентифицирующемся пользователе. Передача SID помогает предотвратить несанкционированный доступ к рабочему столу, например если взять и ввести пароль одного пользователя, а попробовать получить доступ к столу другого.) Внутри MSV1_0 вызывается функция
LsaApLogonUserEx(
, где имя пользователя и пароль проходят аутентификацию при помощи базы данных SAM. Если аутентификация успешна, там же создается сессия входа в систему: вызывается) LsaCreateLogonSession(
, и ей присваивается LogonID (LUID), который генерируется пакетом аутентификации. После этого MSV1_0 добавляет специальную информацию к сессии с помощью вызова) LsaAddCredential(
. Обычно это имя пользователя, имя домена и контрольные суммы LM/NT-хеша пароля. Эта информация впоследствии понадобится, если пользователь попытается получить доступ к удаленным узлам.) Далее Winlogon дожидается ответа от LSA по поводу введенных учетных данных.
После успешной аутентификации пользователя запускается инициализация пользовательской оболочки (User Shell). Пользовательская оболочка — совокупность процессов, запущенных от лица конкретной учетной записи.
-
Просто взять и создать пользовательскую оболочку, например с помощью обычного
CreateProcess(
, не получится. Сначала) lsass.
вызывает функциюexe NtCreateToken(
для создания токена доступа. В этом токене будет содержаться информация о самом пользователе. Именно этот токен в дальнейшем станет использовать) Winlogon.
для создания процесса от лица аутентифицированного пользователя.exe Возможно, у тебя сразу появилась коварная мысль: «А могу ли я сам генерировать токены?» Как бы да и как бы нет. Для успешного создания токена требуется привилегия
SeCreateTokenPrivilege
, которой обладает толькоlsass.
. Если у нас есть эта привилегия, то мы сможем нафантазировать что душе угодно. Абсолютно любой токен — любые группы, привилегии, вне зависимости от каких‑либо глобальных настроек и конфигураций. Например, я получал права на выполнение кода от лица группы.exe И ставил SID = 0.
Дополнительно
Winlogon.
собирает информацию о пользовательской среде. Информация эта самая разная. Заострю внимание на начальном процессе, он же системный шелл, — процессе, который будет порождать остальные процессы в системе от лица пользователя и применяя все установленные настройки пользовательского профиля. Все эти данные хранятся вexe HKLM\
. В ключеSOFTWARE\ Microsoft\ Windows NT\ CurrentVersion\ Winlogon Userinit
по умолчанию указан процессuserinit.
, который как раз таки восстанавливает настройки профиля пользователя. А в ключеexe shell
— системный шелл, обычно этоexplorer.
.exe Сначала идет обращение именно к
Userinit
, программа запускается, выполняется инициализация среды, а затемuserinit.
обращается к ключуexe shell
и порождает системный шелл. После этого процессUserinit
завершается. Собственно, ровно по этой причине мы и не видим родительского процесса уexplorer.
—exe userinit.
уже завершился.exe Пользователь заходит в систему и получает доступ к своему рабочему столу.
Инициализация LSA
Именно LSA играет ключевую роль в процессе аутентификации пользователя. Каким образом LSA будет инициализировать наши вредоносные SP, AP и NP?
При запуске устройства LSA автоматически подгружает все зарегистрированные SP, реализованные в виде DLL, в свое адресное пространство. Все зарегистрированные DLL находятся по следующему пути:
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages
Если этот ключ пустой, то используется значение по умолчанию:
kerberos"\0"msv1_0"\0"schannel"\0"wdigest"\0"tspkg"\0"pku2u"\0
Все эти DLL указываются без полного пути. Microsoft рекомендует помещать SP в папку %systemroot%/
. Далее у каждого SP вызывается функция SpLsaModeInitialize(
, благодаря которой LSA получает специальную таблицу SECPKG_FUNCTION_TABLE
, содержащую указатели на функции. Они реализуют данный пакет безопасности. Выглядит это примерно вот так:
SECPKG_FUNCTION_TABLE SecurityPackageFunctionTable[] ={ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, SpInitialize, SpShutDown, SpGetInfo, SpAcceptCredentials, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }};NTSTATUS NTAPI SpLsaModeInitialize(ULONG LsaVersion, PULONG PackageVersion, PSECPKG_FUNCTION_TABLE * ppTables, PULONG pcTables){ *PackageVersion = SECPKG_INTERFACE_VERSION; *ppTables = SecurityPackageFunctionTable; *pcTables = 1; return 0;}
Если SpLsaModeInitialize(
успешно вернула таблицу, то LSA вызывает SpInitialize(
, которой передает структуру LSA_SECPKG_FUNCTION_TABLE
. В этой структуре содержатся указатели на функции, которые предоставляет LSA для использования внутри SP. Например, функцию CreateToken(
можно использовать для создания токена (это не токен доступа, а токен, который генерируется во время выстраивания контекста в клиент‑серверных приложениях).
Третьей вызывается SpGetInfo(
, благодаря которой LSA получает информацию о пакете. Например, его имя, описание и версию. Эта информация будет отображаться при вызове функции EnumerateSecurityPackages(
:
NTSTATUS NTAPI SpGetInfo(PSecPkgInfoW PackageInfo){ PackageInfo->fCapabilities = SECPKG_FLAG_ACCEPT_WIN32_NAME | SECPKG_FLAG_CONNECTION | SECPKG_FLAG_LOGON; PackageInfo->Name = (SEC_WCHAR*)L"MishaSSP"; PackageInfo->Comment = (SEC_WCHAR*)L"SSP with a wide Russian soul"; PackageInfo->wRPCID = SECPKG_ID_NONE; PackageInfo->cbMaxToken = 0; PackageInfo->wVersion = 1337; return 0;}
Далее LSA загружает все доступные пакеты аутентификации (AP). Их список извлекается из следующего ключа реестра:
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Authentication Packages
В каждом из них будет вызвана функция LsaApInitializePackage(
, в ней LSA передаст таблицу LSA_DISPATCH_TABLE, содержащую все функции LSA, которые может дергать AP. AP, в свою очередь, должен заполнить последний параметр функции, указав свое имя. Это имя LSA использует, чтобы определить, к какому AP хочет получить доступ программа, путем вызова LsaLookupAuthenticationPackage(
.
LSA_DISPATCH_TABLE DispatchTable;NTSTATUS LsaApInitializePackage(_In_ ULONG AuthenticationPackageId, _In_ PLSA_DISPATCH_TABLE LsaDispatchTable, _In_opt_ PLSA_STRING Database, _In_opt_ PLSA_STRING Confidentiality, _Out_ PLSA_STRING* AuthenticationPackageName){ // Сохраняем адреса функций DispatchTable.CreateLogonSession = LsaDispatchTable->CreateLogonSession; DispatchTable.DeleteLogonSession = LsaDispatchTable->DeleteLogonSession; DispatchTable.AddCredential = LsaDispatchTable->AddCredential; DispatchTable.GetCredentials = LsaDispatchTable->GetCredentials; DispatchTable.DeleteCredential = LsaDispatchTable->DeleteCredential; DispatchTable.AllocateLsaHeap = LsaDispatchTable->AllocateLsaHeap; DispatchTable.FreeLsaHeap = LsaDispatchTable->FreeLsaHeap; DispatchTable.AllocateClientBuffer = LsaDispatchTable->AllocateClientBuffer; DispatchTable.FreeClientBuffer = LsaDispatchTable->FreeClientBuffer; DispatchTable.CopyToClientBuffer = LsaDispatchTable->CopyToClientBuffer; DispatchTable.CopyFromClientBuffer = LsaDispatchTable->CopyFromClientBuffer; // Возвращаем имя нашего AP (*AuthenticationPackageName) = (LSA_STRING*)LsaDispatchTable->AllocateLsaHeap(sizeof(LSA_STRING)); if (NULL != (*AuthenticationPackageName)) { (*AuthenticationPackageName) = (LSA_STRING*) LsaDispatchTable->AllocateLsaHeap(sizeof(LSA_STRING)); (*AuthenticationPackageName)->Buffer = (char*) LsaDispatchTable->AllocateLsaHeap((ULONG)strlen ("myssp") + 1); if (NULL != (*AuthenticationPackageName)->Buffer) { (*AuthenticationPackageName)->Length = strlen("myssp"); (*AuthenticationPackageName)->MaximumLength = strlen("myssp") + 1; strcpy( (*AuthenticationPackageName)->Buffer, "myssp"); return 0x00000000L; // STATUS_SUCCESS } return 0xC0000002; // STATUS_NOT_IMPLEMENTED }}
Эксплуатация
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»