Содержание статьи
Что мы знаем про сессии и сервисы в Windows? Да практически ничего, кроме того, что они существуют. Что это за сущности, с чем их едят заматерелые хакеры? Как можно оценить сессию с точки зрения обеспечения защищенности и безопасности в Windows? Сегодня мы об этом и поговорим, попытаемся, так сказать, пролить свет на эту загадку.
WARNING
Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.
Что имеем?
Как я неоднократно говорил, отсутствие в свободном доступе достаточного/исчерпывающего количества информации относительно какой-либо технологии Windows - однозначный признак того, что архитекторы и разработчики системы хотят сохранить в тайне ее детали, поскольку их раскрытие может скомпрометировать всю систему безопасности. Так, например, обстоят дела с RPC или PatchGuard.
Аналогичная ситуация складывается с сессиями в Windows. Многие айтишники что-то там про них слышали, еще меньшей части компьютерного народа знакомо слова "Session 0".
Понятие "сессии" на самом деле не так сложно. Можно говорить о ней, как о некоем временном промежутке работы совокупности программ для одного пользователя. Но при этом сессии являются важной частью обеспечения безопасности системы и защиты пользовательских данных. Это словно оболочка, связывающая все действия пользователя, запущенные программы и сам десктоп.
Рассмотрим все это поподробнее.
Что такое "Сессия"?
Windows изначально проектировалась как многопользовательская система. И это было сделано путем реализации так называемых "терминальных сессий". Здесь надо помнить про то, что "терминальная сессия" и "сессия с момента захода в систему через winlogon.exe" - немного разные вещи. Терминальные сессии создаются и управляются сессионным менеджером smss.exe - процессом, который стартует в системе одним из первых. Winlogon-сессии и процессы как бы "живут внутри" терминальной сессии.
Для того, чтобы получить ID-номер терминальной сессии можно использовать функцию LsaGetLogonSessionData с последующим перечислением Winlogon-сессии посредством функции LsaEnumerateLogonSessions. Также можно получить ID сессии путем вызова GetTokenInformation с параметром TokenSessionId, после получения первичного токена процесса (функция OpenProcessToken). У сессии есть ряд своих приватных структур, которые используются для управления памятью.
У сессии есть свое адресное пространство, которое содержит копии данных, модифицированных драйвером графической подсистемы Win32k.sys, саму копию Win32k.sys, а также немодифицированные данные и различные драйвера, загруженные сессией. У сессии есть пространство вьюшек - виды десктопа.
И, разумеется, у сессии есть свой пул памяти. Между сессиями всех пользователей можно взаимодействовать на программном уровне. Это делается посредством пайпов, сокетов и глобальных эвентов. А вот посылать месседжи в другую сессию не выйдет.
Примечателен и любопытен с точки зрения системной безопасности тот факт, что до появления Windows Vista системные сервисы, winlogon.exe и клиент-серверная подсистема csrss.exe (о которой я уже не раз писал), стартовали как часть "нулевой сессии" ("Session 0") вместе с первым залогиневшимся клиентом, а все последующие залогинившиеся пользователи нумеровались как "Session 1", "Session 2", и т.д. Кстати, сколько у нас там сейчас в интернете остается пользователей ХР? ;).
А теперь самое интересное - эта ситуация стала напоминать забавную историю "кто первый встал - того и тапки", т.е. первый же залогинившийся в систему юзер получал привилегии "Session 0", т.е. мог запросто получить системные права, ведь важнейшие системные сервисы оказывались по соседству с простыми пользовательскими приложениями, такими правами не наделенными. Чем это грозило? Например, злобными shatter-аттаками, когда окну посылается сообщение (да-да, с использованием функции SendMessage) с ядерной начинкой внутри в виде шеллкода, повышающего привилегии. Можно было получить доступ к расшаренным секциям системных процессов, если те были неправильно защищены. Можно было скомпрометировать объекты "\BaseNamedObjects" (кто не знает - в гугл). Одним словом, способов в очередной раз поиздеваться над системой было предостаточно.
Однако, с выпуском Windows Vista, данную лавочку прикрыли. "Session 0" была надежно изолирована от пользовательских приложений. Так думали в Microsoft :).
По-другому думал неугомонный румын ("цыган", хотел написать ;)) Алекс Ионеску, которого очень хорошо знают все, кто хоть как-то связан с системным программированием и разработкой ОС по типу Windows. Действительно талантливый чувак, один из разработчиков ReactOS, если мне не изменяет память. Пытливый Ионеску нарыл способ приаттачиться в "Session 0". Способ хоть и весьма условный, однако работающий. В Windows 7 эта проблема была окончательно устранена.
Интерактивные сервисы - казнь египетския на голову Microsoft
Windows для прикладных и системных тру-кодеров предоставляет возможность создания сервисов - программ, крутящихся на заднем фоне, особо не мешающих пользователям и что-то там потихоньку считающих. Кто не в теме - в качестве некоего аналога могу привести демоны в *nix-like операционных системах. Ничего сложного в создании Win сервисов нет, документации полно, примеров еще больше, и ими активно пользуются как честные программисты, так и малварщики.
Есть такая возможность создания интерактивного сервиса - с флагом SERVICE_INTERACTIVE_PROCESS при вызове функций CreateService() или ChangeServiceConfig().
Когда менеджер сервисов (services.exe) создает процесс для интерактивного сервиса (сорри за тавтологию :), он присоединяет его к "Winsta0" (начальной рабочей станции, о них - ниже), а не к рабочей станции самого процесса. Чтобы сделать этого, процесс сервиса должен иметь права SYSTEM, потому что потом ему придется взаимодействовать с интерактивным десктопом и самим пользователем. Это может привести к очень плачевным результатам - атакам на повышение привилегий, основываясь на том, что интерактивные процессы функционируют в системе с правами SYSTEM и привилегиями "trusted computing base" (TCB).
Изоляция "Session 0" может привести к проблеме с сервисами, которым необходимо отображение пользовательского интерфейса. Поскольку сервис теперь выполняется в другой сессии (по сравнению с десктопом), пользовательский интерфейс не будет виден конечным пользователям и интерактивный сервис может оказаться в «зависшем» состоянии.
В Windows Vista решение этой проблемы состоит в том, что пользователям предоставляется возможность временного переключения в "Session 0" для взаимодействия с интерактивным сервисом.
В общем, намудрили товарищи из Microsoft, не смогли переплюнуть золотое правило: "Когда нельзя, но очень хочется, тогда можно".
Осторожно, двери закрываются! Следующая станция... "Windows"?
Да-да, системным кодерам должно быть знакомо понятие WindowStation (CreateWindowStation()). Зачем оно нужно? Ну хотя бы для того, чтобы всегда иметь ввиду, что если твой код должен быть внедрен в системный процесс или сервис (посредством подмены контекста потока), он выполняться не будет в силу несоответствия WindowStation, потому у как юзермодных приложений это будет "\Windows\WindowStations\WinSta0", а у сервиса - "\Windows\WindowStations\Service-0x0-3e7$". Это надо обязательно иметь в виду, например при создании кейлоггеров.
Как можно получить полный доступ к интерактивной рабочей станции и десктопу «winsta0\default»? Смотрим код:
winstaHandle = OpenWindowStation("winsta0", FALSE,
WINSTA_ACCESSCLIPBOARD |
WINSTA_ACCESSGLOBALATOMS |
WINSTA_CREATEDESKTOP |
WINSTA_ENUMDESKTOPS |
WINSTA_ENUMERATE |
WINSTA_EXITWINDOWS |
WINSTA_READATTRIBUTES|
WINSTA_READSCREEN|
WINSTA_WRITEATTRIBUTES)) ;
SetProcessWindowStation(winstaHandle);
desktopHandle = OpenDesktop("default", 0, FALSE,
DESKTOP_CREATEMENU |
DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE|
DESKTOP_HOOKCONTROL |
DESKTOP_JOURNALPLAYBACK |
DESKTOP_JOURNALRECORD |
DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP |
DESKTOP_WRITEOBJECTS));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb= sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";
if (!CreateProcessAsUser(
hToken,
NULL,
"cmd.exe",
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
));
Полный вариант кода ты сможешь найти здесь - http://support.microsoft.com/kb/165194
INFO
Единственный способ что-то сделать вне своей терминальной сессии — это запустить отдельный процесс в этой сессии посредством CreateProcessAsUser с нужным токеном
WWW
Как всегда MSDN тебе на помощь - http://msdn.microsoft.com/en-us/library/windows/desktop/ms687105(v=vs.85).aspx
Подытожим...
Тема сессий, рабочих станций и сервисов в Windows далеко не изучена. Уверен, что там если покопаться хорошенько - не одну химеру на свет божий можно будет вытащить.
В погоне за безопасностью команда Windows хорошенько постаралась осложнить жизнь как простым программистам, так и мальварщикам. С выходом операционок Windows Vista+, начали успешно отваливаться многие коммерческие VNC-решения, перестали работать кейлоггеры. И все это - в силу попыток изолировать рабочие станции, десктопы и сессии друг от друга.
Засим закончу. Удачного компилирования и да пребудет с тобой Сила!