On-Line Библиотека www.XServer.ru - учебники, книги, статьи, документация, нормативная литература.
       Главная         В избранное         Контакты        Карта сайта   
    Навигация XServer.ru






 

Изменение LOGIN/PASSWORD под WINNT

Введение


Частой разновидностью атак на Windows NT-системы заключается в попытке получения имен пользователя и контрольных сумм с LM/NT-паролей, используя такие программы, как L0phtCrack или tcpdump-smb. Последние используются, чтобы получить нелегальный доступ к разделяемым файловым и принтерным ресурсам на атакуемых серверах. Чтобы суметь воспользоваться парами "имя пользователя/контрольная сумма с пароля" вместо обычных пар "имя пользователя/пароль", атакующий должен воспользоваться неким модифицированным SMB-клиентом. Обычно, атакующими используется SAMBA (решение на базе SMB/CIFS для платформ Unix), ввиду доступности исходного текста, что позволяет без каких-либо затруднений адаптировать программу для соответствующих нужд.

Однако, использование SAMBA в то же время ограничивает возможности атаками на разделяемые ресурсы файлов и принтеров. Хотя последняя версия SAMBA включает начальную поддержку протокола MS RPC, она поддерживает далеко не все возможности, предоставляемые стандартными утилитами администрирования для Windows NT, и, скорей всего, никогда не будет. Данный документ разъясняет, как изменить сертификат работающего в Windows NT Server/Workstation пользователя, что автоматически позволяет атакующему воспользоваться любой "родной" программой в Windows NT, которая пользуется именем пользователя и контрольными суммами для проверки аутентификации, такими как редактор реестра (regedit32.exe), менеджер пользователей для доменов (usrmgr.exe), менеджер управления сервисами и тп.

Описание процесса входа пользователя в Windows NT и аутентификации


Существует три основных элемента, задействованных в процессе входа в систему и аутентификации: logon-процессы, процесс сервера LSA, и аутентификационные пакеты.

  • Logon-процессы - компоненты, которым операционная система доверяет производить мониторинг устройств ввода/вывода на предмет попыток входа в систему (сеть считается устройством).

  • Процесс сервера LSA (Local Security Authority) - процесс пользовательского режима (LSASS.EXE), который учитывает выбранную идеологию безопасности на локальной системе, занимается аутентификацией пользователя и передает сообщения для протоколирования в Event Log.

  • Аутентификационные пакеты - компоненты (в виде DLL), которые производят непосредственную аутентификацию пользовательских сертификатов, создают новую сессию входа в систему LSA для данного пользователя и возвращают наборы идентификаторов (SID) и другую информацию, которую необходимо включить в Token-объект. Он описывает контекст прав пользователя на операции в NT. Помимо этого, аутентификационный пакет может проассоциировать один или несколько дополнительных фрагментов информации сертификата с сессией пользователя для дальнейшего использования.

LSA подгружает эти библиотеки в момент загрузки системы, считав записи в ключе реестра:
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa under
AuthenticationPackages

Logon-процессы фиксируют попытки входа и посылают данные сертификата пользователя в LSA для аутентификации. Эта аутентификация осуществляется аутентификационными пакетами. Каждые logon-процесс должен зарегистрировать себя в LSA при загрузке системы, в тот же момент он выбирает наиболее надежный аутентификационный пакет.

API, который должен быть представлен в аутентификационных пакетах и API, доступный logon-процессу документированы в файле LSAAUTH.HLP из Windows NT DDK.

WinLogon и MsV1_0


Стандартный logon-процесс для интерактивных входов в систему Windows NT назывется Winlogon (WINLOGON.EXE). Он перехватывает попытки входа в систему с клавиатуры.

При загрузке WinLogon регистрирует себя в LSA в качестве logon-процесса, вызывая функцию LsaRegisterLogonProcess. Таким образом он получает хэндл logon-процесса LSA и устанавливает LPC соединение с портом LSA аутентификации (\LsaAuthenticationPort), который будет использован для обмена информацией в случае входа в систему, выхода из нее и проведения операций над паролем.

Потом он получает идентификатор для стандартного аутентификационного пакета, MSV1_0 (MSV1_0.DLL), вызвав LsaLookupAuthenticationPackage. Это тот самый пакет, с помощью которого будет производиться аутентификация сертификата пользователя.

Какждый раз, когда WinLogon пытается обеспечить вход пользователя в систему, он вызывает LsaLogonUser, указывая собственный хэндл logon-процесса LSA, идентификатор пакета Msv1_0 и имя пользователя с паролем в вызове.

Процесс завершается в LSAApLogonUserEx (функция находится в MSV1_0.DLL), где имя пользователя и пароль проходят аутентификацию при помощи удаленной или локальной базы данных SAM, и где, если аутентификация успешно пройдена, создается сессия входа в систему путем вызова LsaCreateLogonSession и присвоения ей LogonID (LUID), который генерируется пакетом.

После этого MSV1_0 добавляет дополнительные сертификаты к сессии, с помощью вызова LsaAddCredential. Такой сертификат включает имя пользователя, имя домена и контрольные суммы LM/NT его/ее пароля.

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

MSV1_0 получает из базы данных SAM также SID пользовательского экаунта и группы, к которым тот принадлежит, и передает эту информацию процессу LSA-сервера, который, в свою очередь, получает список привилегий, соответствующий экаунту и группам, и вызывает NT Executive чтобы создать Access Token (идентифицирующий пользователя и его права). Последний передается приложению WinLogon, которое запускает оболочку, как правило, EXPLORER.EXE.

Access Token связывается со своей LSA-сессией входа в систему при помощи идентификатора AuthenticationID, который представляет собой не что иное как LogonID, сгенерированный аутентификационным пакетом.

Изменение сертификата MSV1_0


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

Не стоит забывать, что многое в данном случае основывается на интуиции и некоторые выводы могут быть неточными.

Процесс LSA-сервера хранит сессии в едином списке. Существует глобальная структура, в которой он хранит указатель на этот список и количество созданных сессий входа в систему ("стопроцентного" способа нахождения это структуры нет, она находится где то в LSASERV.DLL, библиотеке, используемой LSA, где находятся функции и структуры сессий входа в систему).

struct LsaLogonSessionArray { // Указатель на список uint32_t pLogonSessionsList; // количество сессий входа uint32_t logonSessionsCount; }; pLogonSessionsList - указатель на простой список сессий входа в систему. Формат элемента списка таков: struct LsaLogonSession { // Указатель на следующую сессию uint32_t pNextLogonSession; // LogonId (LUID) uint32_t logonIDLow; uint32_t logonIDHigh; // Указатель на имя пользователя в Unicode uint32_t pUNICODE_USERNAME; // Указатель на имя пользователя в Unicode uint32_t pUNICODE_DOMAINNAME; // Неизвестный элемент. Похоже, указатель на // другую структуру, где среди прочего // находится RID пользователя uint32_t unkown1; // Видимо количество ссылок на logon-сессию uint32_t referenceCount; // Указатель на массив сертификатов uint32_t pLsaCredentialsArray; }; pLsaCredentialsArray указывает на другую структуру под названием LsaCredentialsArray. Если pLsaCredentials == 0 значит сессия входа в // систему не имеет никаких связанных с нею // сертификатов. struct LsaCredentialsArray { // Неизвестно uint32_t unknown1; // Неизвестно uint32_t unknown2; // указатель на сертификат uint32_t pLsaCredentials[]; }; В ходе данного исследования не рассматривались сессии с более чем одним набором сертификата, однако, есть основания считать это массивом. pLsaCredentials в конце концов приводит нас к сертификату, созданному аутентификационным пакетом // сертификат struct LsaCredentials { // Неизвестно uint32_t unknown1; // Значение главного ключа в сертификате STRING PrimaryKey; // Сертификат STRING Credentials; }; Используется STRING следующего формата: struct STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; };

Каждому сертификату должно быть присвоено значение в PrimaryKey, строке, которую впоследствии аутентификационный пакет может использовать, чтобы ссылаться на данный сертификат при вызове LsaGetCredentials. MSV1_0 в качестве значения PrimaryKey использует "Primary".

Сертификат не обязательно представляет из себя строку символов. В случае MSV1_0 Credentials.Buffer указывает на структуру типа:

struct MsvCredentials { UNICODE_STRING UNICODE_DOMAIN; UNICODE_STRING UNICODE_USERNAME; uint8_t NTHash[16]; uint8_t LMHash[16]; UCHAR domainname[UNICODE_DOMAIN.Length]; UCHAR username[UNICODE_USERNAME.Length]; };

Таковы данные, которые использует LAN Manager и другие службы, которые прибегают к помощи аутентификационного пакета MSV1_0 для доступа к удаленным узлам. Изменив их, можно проводить SMB/CIFS/MS RPC атаки с помощью украденных из Windows NT Workstation/Server имени пользователя/контрольной суммы с пароля.

UNICODE_DOMAIN и UNICODE_USERNAME не обычные строки в Unicode, элемент Buffer не прямой указатель на Unicode-строку, а смещение от начала структуры MsvCredentials. MSV1_0 поступает когда вызывает LsaAddCredentials так, чтобы сделать эти данные независимыми от адресного пространства процесса.

Кроме этого стоит отметить, что в Разделе 4.2 MSV1_0 (Credentials Formats) файла LSAAUTH.HLP сказано, что сертификаты, хранимые MSV1_0 не содержат имени домена, хотя на самом деле это не так.

Учитывая все вышесказанное, последовательность действий для изменения сертификата входа в систему следующая.

Получить Access Token AuthenticationId текущего пользователя. Это легко можно сделать с помощью WIN32 API:

// Получаем Access Token текущего порцесса OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken); // Получаем статистическую информацию GetTokenInformation( hToken, TokenStatistics, &tokenstats, sizeof(tokenstats), &len) // элемент AuthenticationId возвращенной // структуры типа TOKEN_STATISTICS // Содержит идентификатор входа в систему // logon ID соответствующий данному Token. logonID = tokenstats.AuthenticationId;

    Получить указатель на LsaLogonSessionArray. Как сказано выше, стопроцентной последовательности действий для получения этого указателя нет, поэтому использовался такой метод:

    • Получить хэндл hProcess на образ в памяти процесса сервера LSA, используя OpenProcess c флагом PROCESS_ALL_ACCESS (для этого нужно иметь права отладчика).

    • Вставить DLL в адресное пространство LSASS.EXE путем создания удаленной нити подпроцесса (thread). Этот DLL содержит функцию, которая будет выполнять всю работу.

    • Эта функция вызывает GetModuleHandle чтобы получить hModule на MSV1_0 и получает адрес функции LsaApInitializePackage с помощью GetProcAddress().

    LsaApInitializePAckage - функция, которую должен иметь каждый аутентификационный пакет, она вызывается LSA после загрузки пакета DLL. В этом выхове аутентификационный пакет получает указатель на LsaDispatchTable. Эта таблица содержит указатели на функции LSA доступные аутентификационным пакетам, например, LsaAddCredential и LsaGetCredentials (имплементированы в LSASRV.DLL).

    • Прибавив 38h к адресу LsaApInitializePackage получить адрес переменной, где msv1_0.dll хранит укахатель на функцию LsaAddCredential.

    • Получить адрес LsaAddCredential из этой переменной и прибавить к ней 4.

      Таким образом можно получить адрес объекта CRITICAL_SECTION, который LSASRV.DLL использует для синхронизации доступа к структуре LsaLogonSessionArray.

    • Прибавив 1Ch к этому адресу получить указатель на LsaLogonSessionArray.

    • Имея адрес LsaLogonSessionArray найти в списке LsaLogonSession с LogonID, соответствующим AuthenticationID token'а. Это осуществляется при помощи ReadProcessMemory и hProcess на LSASS.EXE

    • Теперь остается только подменить сертификат MSV1_0, связанный с этой LsaLogonSession.

Это наименее глубокий способ изменения сертификата и позволит вам только изменить контрольные суммы LM и NT пользователя. Почему? Потому что они имеют фиксированную длину (16 байт каждая) и достаточно просто записать поверх них новые. Однако имя пользователя и домена - строки в Unicode, которые изменяют длину и вы должны заново выделять память под новый блок сертификата, чтобы заменить их более длинными. (Например, если имя пользователя - "MyUser" и вы хотите заменить его на "MyAnotherUser", вам понадобится больший буфер для новой Unicode-строки).

В данном случае это может быть решено путем очередного введения dLL в адресное пространство LSASS.EXE и вызовами LsaDelCredential и LsaAddCredential как поступил бы MSV1_0, чтобы заменить целиком сертификат на новый с другими Именем пользователя и паролем.

Заключение. Изменение сертификатов входа в систему позволяет атакующему использовать Windows NT атаки с помощью украденных имен пользователя/контрольных сумм. Оно позволяет удаленное управление атакуемым сервером, которое ранее было бы невозможным без самих паролей. Оно не является новой дырой в безопасности само по себе, но, несомненно, расширяет возможности взломщика.



Литература по сетям Windows