Привет! В общем пытаюсь от WTSQueryUserToken получить токен LocalSystem Code (Text): WTSQueryUserToken(0, &hToken); Запускаю сервис с системной привилегией SE_TCB_NAME на рабочей станции Service-0x0-3e7$ (NT AUTHORITY\система, SID S-1-5-18) и из него вызываю WTSQueryUserToken. На всех актуальных виндах (7, 10, 11) выдаёт одно и тоже - ERROR_NO_TOKEN (An attempt was made to reference a token that does not exist). При этом из-под юзерской сессии WTSQueryUserToken отрабатывает превосходно, выдавая токен юзера. MSDN пишет Что я делаю не так? --- Сообщение объединено, Sep 20, 2023 --- Возможно пользователь (в частности LocalSystem) может разлогиниться после выполнения всех своих задач. Нашёл на одном форуме информацию, что сервис нужно создать с одной из групп загрузки, чтобы он стартовал до того момента, как первый пользователь успеет залогиниться. Сейчас сервис стартует в автоматическом режиме SERVICE_AUTO_START с запуском системы и менеджера SC Manager. Позже попробую добавить группу загрузки ProfSvc_Group посмотрю изменится ли что-то.
k3rnl, WTSQueryUserToken() возвращает "ERROR_NO_TOKEN", если в текущем сеансе нет зареганых юзеров. И зачем вам вообще токен пользователя System? Вроде это было актуально на ХР, когда все дружно жили в одном сеансе\сессии. Начиная с висты лафа-же закончилась, т.к. юзеры System\Service\Network закрылись теперь в изолированной сессии(0), а для смертных осталась старая сессия(1). Если вы и получите системный токен, то использовать его в сессии(1) не сможете, т.к. в структуре токена прописывается и сессия, внутри которой действителен данный токен. С содержимым токенов можно ознакомиться в WinDbg так: (1)берём произвольный процесс, (2)запрашиваем указатель на токен родителя, (3)просматриваем его. Вот пример (кроликом пусть будет AkelPad): Spoiler: 0: kd> !process 0 0 AkelPad.exe Code (Text): 0: kd> !process 0 0 AkelPad.exe ------------------------------- PROCESS fffffa8003f08060 SessionId: 1 Cid: 0500 Peb: 7efdf000 ParentCid: 0618 DirBase: 57336000 ObjectTable: fffff8a001da57a0 HandleCount: 238. Image: AkelPad.exe 0: kd> !process fffffa8003f08060 1 ---------------------------------- PROCESS fffffa8003f08060 VadRoot fffffa8003a99990. Vads 305. Clone 0. Private 1718. Modified 11912. Locked 0. DeviceMap fffff8a002166e30 Token fffff8a002e3ca30 <---- адрес токена //****** BasePriority 8 CommitCharge 2886 Job fffffa80027bc2f0 0: kd> dt _token fffff8a002e3ca30 --------------------------------- nt!_TOKEN +0x000 TokenSource : _TOKEN_SOURCE +0x010 TokenId : _LUID +0x018 AuthenticationId : _LUID +0x020 ParentTokenId : _LUID +0x028 ExpirationTime : _LARGE_INTEGER 0x7fffffff`ffffffff +0x030 TokenLock : 0xfffffa80`0279d710 _ERESOURCE +0x038 ModifiedId : _LUID +0x040 Privileges : _SEP_TOKEN_PRIVILEGES <---- Привилегии //****** +0x058 AuditPolicy : _SEP_AUDIT_POLICY +0x074 SessionId : 1 <------------------- Номер сеанса //****** +0x078 UserAndGroupCount : 0xf +0x07c RestrictedSidCount : 0 +0x080 VariableLength : 0x2bc +0x084 DynamicCharged : 0x400 +0x088 DynamicAvailable : 0 +0x08c DefaultOwnerIndex : 4 +0x090 UserAndGroups : 0xfffff8a0`02e3cd40 _SID_AND_ATTRIBUTES +0x098 RestrictedSids : (null) +0x0a0 PrimaryGroup : 0xfffff8a0`02bca750 Void +0x0a8 DynamicPart : 0xfffff8a0`02bca750 -> 0x501 +0x0b0 DefaultDacl : 0xfffff8a0`02bca76c _ACL +0x0b8 TokenType : 1 ( TokenPrimary ) +0x0bc ImpersonationLevel : 0 ( SecurityAnonymous ) +0x0c0 TokenFlags : 0x2000 +0x0c4 TokenInUse : 0x1 '' +0x0c8 IntegrityLevelIndex : 0xe +0x0cc MandatoryPolicy : 3 +0x0d0 LogonSession : 0xfffff8a0`021ee080 _SEP_LOGON_SESSION_REFERENCES +0x0d8 OriginLogonSession : _LUID +0x0e0 SidHash : _SID_AND_ATTRIBUTES_HASH +0x1f0 RestrictedSidHash : _SID_AND_ATTRIBUTES_HASH +0x300 pSecurityAttributes : 0xfffff8a0`02ddfac0 _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION +0x308 SessionObject : 0xfffffa80`03a7e370 Void +0x310 VariablePart : 0xfffff8a0`02e3ce30 0: kd> Из своего сеанса(0), система забрасывает в юзерский сеанс(1) двух диверсантов - это файлы winlogon.exe, и csrss.exe. При этом в их токене сеанс сразу меняется с 0 на 1, чтобы юзер не смог снять его дубликат. Более того, имеется и доп.защита от несанкционированного доступа к системным файлам на уровне фишки "Integrity Level" - процесс с меньшим значением IL не сможет получить доступ к процессу с более высоким IL. Если запустить "Process Explorer", можно убедиться в этом.
Marylin, благодарю за ответ, но сразу сделаю несколько уточнений. Я не первый день работаю с процессами с повышенными правами и прекрасно в этом разбираюсь (это чтобы сразу отбросить вот этот ненужный контент про доступы, сессии, системные токены и т.д.). Что мешает запустить процесс с правами System в юзерской сессии 0+n (RtlCreateUserProcess с хендлом системного процесса) и из него сделать CreateProcessAsUser в сессию 0? Правильно - ничего. Тут даже нет никаких проблем чтобы перейти в терминальную сессию на интерактивную рабочую станцию WinSta0 и рабочий стол Default (MS типа хотела прикрыть эту тему начиная с Windows 10 build 1803, но ничего у неё не получилось). Где можно спокойно работать с окнами под тем самым аккаунтом NT AUTHORITY\SYSTEM. Касаемо токена - есть куча инструментария для его олицетворения и приведение в полное состояние. Integrity Level интересная тема, в своё время разбирался в ней. Каждый уровень увеличивает RID на шаг равный 0x1000. Перепрыгнуть через два и более шага невозможно, только постепенное увеличение SECURITY_MANDATORY. Именно так и работает защита в ОС. И именно поэтому не существует доступа к гипервизору под ядром (SECURITY_MANDATORY_SECURE_PROCESS_RID, SID: S-1-16-28672), т.к. его RID равен 0x00007000L. При этом ближайший RID это SECURITY_MANDATORY_PROTECTED_PROCESS_RID (SID: S-1-16-20480), который равен 0x00005000L. Но это всё мы с вами сейчас не в ту сторону копаем. Задача совершенно в другом. Я знаю что такое ERROR_NO_TOKEN, вопрос в другом - почему пользователь LacalSystem разлогинен, и поэтому я не могу взять его токен? С другой стороны, нет никаких проблем захватить токен процесса lsass.exe (который по своим параметрам (привилегии и т.д.) полностью повторяет токен процесса System), даже в Windows 11 (сам процесс lsass.exe имеет protect LSA, но его токен не защищен). Но задача стоит захватить именно токен System.
k3rnl, я сам плаваю в деталях, а потому и спрашиваю без сарказма, если вы можете "запустить процесс с правами System в юзерской сессии 0+n через RtlCreateUserProcess()", то зачем вам токен юзверя System? Ведь успешный старт процесса будет означать, что этот токен у вас уже имеется. Или я что-то не понимаю? Без системного токена с его уровнем IL мы не сможем создать приоритетный процесс, т.к. SRM нас обломает: Ну с переходом из терминальной сессии(0) на интерактивную WinSta0 юзера всё ясно - просто создаём сервис с флагом "SERVICE_INTERACTIVE_PROCESS", тогда диспетчер загрузит службу по дефолтной схеме в станцию "Service-0x0-3e7$" сессии(0), но в момент отображения сервисом окна, переключит станцию на WinSta0 (при этом вроде должен быть активным системный сервис UI0Detect.exe). Вы проверяли активных пользователей в сессии(0)? LsaEnumerateLogonSessions() из Secur32.dll этим занимается. Далее, полученный от неё LUID юзеров передаём в LsaGetLogonSessionData(), чтобы получить в структуру "SECURITY_LOGON_SESSION_DATA" детальную инфу о сессии. Можно заюзать и WTSQuerySessionInformation(), но она "сериализована" и возвращает что-то одно, в то время как первая стреляет сразу дробью. После сбора этой инфы, наверное можно обратно загнать пользователя в сессию (если он разлогинен), например через LogonUser() из Advapi32.dll. Кстати имена трёх юзеров "LocalSystem\Service\Network" это просто алиасы, а фактически "по-батюшке" в формате Domain\Name их возвращает NetWkstaUserGetInfo() из Netapi32.dll. Когда-то я писал утилиту, которая выводит инфу о сессиях (см.скрепку), и у себя на данный момент получил такую картину. Внимание заслуживают здесь столбцы "Domain + UserName" с именами скрытых юзеров в сессии(0) - это LUID: 03e4$=NetworkService, 03e5$=LocalService и 03E7$=SystemLogon:
Marylin, мне был интересен, скажем так, "чистый" токен самого аккаунта. А так да, вы правы, скорее всего токен любого системного процесса ничем не будет отличаться от токена LocalSystem при правильной его настройке. Спасибо за наводку по активным пользователям, позже поэкспериментирую с LSA функциями. Про имена NetworkService, LocalService и SystemLogon (он же LocalSystem) знаю. Что интересно в Windows 11 появились новые LUID формата 03e5$, так же свой LUID имеет и гипервизор. Также есть ещё одно отдельное ото всех окружение - рабочая станция MSSWindowStation и рабочий стол MSSRestrictedDesk, используемые процессом SearchIndexer.exe и его сервисом SearchFilterHost.exe В общем тема интересная, и покопаться во внутренностях ОС достаточно увлекательно.
Ну если ещё в Win10 подвезли уже два новых юзера "UMDF" и "DWM", то вполне возможно на Win11 подтянулись ещё парочка. У меня только 7 и 10, тч проверить новых постояльцев не могу. Кстати их список можно посмотреть в том-же WinDbg, ну или софтом "WinObj". Spoiler: !object \Windows Code (Text): 0: kd> !object \Windows ------------------------ Object: fffff8a0005c7080 Type: Directory Name : Windows Hash Address Type Name ---- ------- ---- ---- 13 fffff8a000f50e10 Directory WindowStations <-----// 26 fffff8a000e99520 Section SharedSection 27 fffffa80018fc090 ALPC Port ApiPort 33 fffffa8002ced950 ALPC Port SbApiPort 0: kd> !object fffff8a000f50e10 ------------------------------- Object: fffff8a000f50e10 Type: Directory Name : WindowStations Hash Address Type Name ---- ------- ---- ---- 03 fffffa8002e15450 WindowStation Service-0x0-3e4$ <-- Network 04 fffffa8002e34e40 WindowStation Service-0x0-3e5$ <-- Service 06 fffffa8003af93f0 WindowStation Service-0x0-3e7$ <-- System 08 fffffa8002b94530 WindowStation msswindowstation <-- ??? 25 fffffa8003a832a0 WindowStation WinSta0 <-- User Угу.. они были ещё в хрюше ХР. Насколько я себе представляю всю эту кухню, отображено на рис.ниже. согласен.. затягивает не по-детски.
В общем получилось на выходе набросать небольшую программку (за основу взял свой старый проект). IDE и компилятор выбрал Pelles C (посмотреть на что способна эта среда, и на удивление очень неплохо себя показала). Может кому-нибудь будет полезен её функционал. Небольшой FAQ как пользоваться: UI0Detect.exe - сервис для перехода в терминальную сессию (то что было вырезано MS начиная с Windows 10 build 1803) Wls0wndh.dll - подпрограмма сервиса UI0Detect.exe (нужна для возврата из терминальной сессии) FDUI0Input.sys - драйвер устройств ввода клавиатура и мышь (начиная с Windows 10 build 1803 был изменён драйвер win32kfull.sys) Code (Text): if (gSessionId != gServiceSessionId) // if (gSessionId != 0) { // функции и события устройств ввода } Файлы UI0Detect.exe и Wls0wndh.dll необходимо разместить в папке Windows\System32 Обязательно установить драйвер FDUI0Input.sys для того, чтобы можно было пользоваться клавиатурой и мышью в сессии 0 И немного о самой программе: из основных - переход в терминальную сессию, создание процессов в терминальной сессии, менеджер привилегий для процессов (двойной клик ЛКМ на списке процессов), снятие защиты с сервиса (пока ещё только наброски, позже расширю функционал). Также организовал на выбор самые мощные (по моему мнению) токены - локальная система (с привилегией SeCreateTokenPrivilege) и доверенный установщик TrustedInstaller (для доступа к особым разделам ОС) - можно переключаться по одному нажатию соответствующей кнопки. LocalSystem TrustedInstaller
Немного пофиксил код и обновил функционал. 1. Обратил внимание, что на медленных ПК (и возможно на Windows 7) может появляться второе окно программы при захвате токена Trusted Installer. Это происходит из-за ожидания остановки сервиса TrustedInstaller и последующего закрытия диалогового окна (EndDialog). Теперь остановка сервиса обрабатывается в отдельном потоке, и EndDialog не ждёт окончания процедуры, тем самым окно больше не дублируется. 2. Сделал функционал по обновлению списков процессов и сервисов через контекстное меню WM_CONTEXTMENU (правой кнопкой мыши -> Update ... List). Не стал мудрить с таймеров, к тому же почему-то в Pelles C отсутствует контрол Timer. Пока что работает так себе, позже доведу до ума. 3. Расширил функционал по созданию системных процессов - теперь можно создавать и в терминальной сессии, и в пользовательском окружении (путём согласия или отказа на соответствующий вопрос). 4. Немного осовременил интерфейс диалогового окна для Windows 11 средствами DwmAPI (DwmSetWindowAttribute - DWMWA_WINDOW_CORNER_PREFERENCE и DWMWA_SYSTEMBACKDROP_TYPE). Добавил угловатости (DWMWCP_ROUNDSMALL) и цвета заголовка окна (переливку в зависимости от картинка рабочего стола (DWMSBT_TABBEDWINDOW) оставил). Выглядит вроде неплохо для технологии времён 3.x и 95 --- Сообщение объединено, Oct 3, 2023 --- Прошу прощения - не заметил утечку памяти. Из прядущего поста не качайте. Пересобрал билд.
alex_dz, спасибо за обратную связь. Обработчик сообщений добавлю. Над GUI менеджерами процессов и сервисов поработаю чуть позже. В той части кода пока только наброски сделал (для проверки основного функционала). Пока думаю что конкретно добавить, лепить всё подряд не хочется, "большой" проект утомляет и со временем начинаешь его забрасывать. Наверно тему отдельную создам в wasm проектах, тут дальше постить не вижу смысла. Вопрос этой темы был решён.