.

Отложенный старт

В предыдущих версиях операционной системы, до Windows Vista, для запуска пользовательских служб было всего две настройки — запуск вручную и автоматический запуск. Автоматический запуск осуществлял менеджер служб при старте системы. Вручную сервис можно было запустить разными способами, но для этого требовалось выполнить некий набор действий. Однако увеличение количества запускающихся при старте системы служб замедляет старт и ухудшает реакцию системы на начальном этапе работы. При этом многие службы на самом деле нет нужды запускать именно в процессе загрузки системы. Такие службы, как веб-сервер или сервер баз данных, не критичны для запуска самой операционной системы и потому могли бы быть запущены и позднее, когда критичные для работы ОС службы уже запущены и работают.

Для решения этой проблемы в Windows Vista для служб была введена еще одна настройка — отложенный старт. Службы, которым назначен такой тип запуска, будут запущены не во время процесса загрузки, а сразу после того, как она закончится. Вместе с тем нельзя забывать о некоторых побочных эффектах такой возможности. Прежде всего, это влияние зависимости служб друг от друга. Если есть служба X, которая зависит от другой службы Y с данным типом старта, то диспетчер управления службами (SCM) проигнорирует эту настройку и запустит сервис Y вне зависимости от установленного флага. Кроме того, теперь нельзя предсказать момент, когда некая служба будет запущена. Если раньше некоторые приложения полагались на то, что к определенному моменту та служба, с которой они работают, должна быть уже запущена, то сейчас такой фокус не сработает. Поэтому, если у вас есть подобного рода службы, не стоит назначать им данный флаг. И наконец, настройка не может быть назначена, если служба находится в какой-либо группе из списка ServiceBootOrder в ключе реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder, который управляет последовательностью загрузки служб и драйверов. Более подробно эта конфигурация разъясняется в статье http://support.microsoft.com/kb/115486/en-us.

Для того чтобы изменить тип запуска службы, можно задействовать утилиту sc, например:

Sc config test start= delayed-auto

Обратите внимание на необходимость пробела между именем параметра со знаком присваивания и значением.

Получить список служб с этим типом запуска можно, например, вот так:

cls
$serviceList = Get-Service
foreach ($service in $serviceList){
   $s = "sc.exe qc "+$service.name
      $r = Invoke-Expression $s
   if ($r -like "*DEMAND_START*") {$r}
}

Этот сценарий выполняет команду sc qc для каждой службы, возвращенной командой get-service, и отображает только те, которые содержат значение DEMAND_START.

Оповещения о состоянии служб

Раньше для того, чтобы получить данные о состоянии службы, клиентское приложение должно было использовать функцию QueryServiceStatusEx и периодически запрашивать статус службы в цикле. Однако это не лучшее решение с точки зрения производительности. В Windows Vista появилась другая возможность, функция NotifyServiceStatusChange. Она позволяет зарегистрировать функцию обратного вызова (callback) в системе, которая будет вызвана SCM, когда произойдет ожидаемое событие. Однако стоит отметить, что NotifyServiceStatusChange нельзя применять к драйверам, которые тоже управляются диспетчером управления службами (SCM).

Службы, управляемые событиями

Есть много случаев, когда процесс службы запущен, то есть его потокам выделяется процессорное время. Однако при этом никакой полезной работы служба не выполняет. В итоге процессорное время тратится впустую. Для того чтобы с этим справиться, в Windows 7/2008 реализована функциональность, позволяющая запускать и останавливать службы, в ответ на определенные события. Эта возможность основана на механизме Event Tracing for Windows (ETW). Администратор может задать события и реакцию на них для определенной службы. Внутри операционной системы это делается посредством функции ChangeServiceConfig2. С точки зрения администратора, можно воспользоваться утилитой sc с параметром qtriggerinfo для получения конфигурации или triggerinfo для установки. Для того чтобы получить весь список служб, для которых заданы события, можно воспользоваться вот таким простым сценарием на powershell:

cls
$serviceList = Get-Service
foreach ($service in $serviceList){
   $s = "sc.exe qtriggerinfo "+$service.name
      $r = Invoke-Expression $s
   if ($r -like "*ИМЯ_СЛУЖБЫ*") {$r}
}

Этот сценарий выполняет команду sc qtriggerinfo для каждой службы, возвращенной командой get-service.

К сожалению, ни WMI-класс WIN32_Service, ни команда get-service не содержат данных ни о событиях, ни о новом методе старта службы.

Безопасность

Службы — очень важная и вместе с тем уязвимая часть системы. Они выполняют важную работу и запущены большую часть времени. Кроме того, они работают с сетью и, как следствие, подвержены сетевым атакам. Поэтому была проведена определенная работа с целью усилить их защиту.

Ограниченные привилегии

Прежде всего, отмечу, что привилегии — это не права доступа. Привилегии управляют доступом к системным ресурсам, в то время как права доступа контролируют доступ к защищаемым объектам. Системные администраторы могут назначать привилегии учетным записям пользователей и групп, а система проверяет возможность доступа пользователя к ресурсу на основе его членства в группах и описателя безопасности, ассоциированного с ресурсом, на основании списков доступа и списков аудита (DACL и SACL).

Список возможных привилегий можно найти на сайте Microsoft http://msdn.microsoft.com/en-us/library/bb530716(v=vs.85).aspx.

Часто службы исполняются от имени различных доменных пользователей или учетной записи LocalSystem. Иногда это дает им совсем не нужные, а порой и вредные привилегии. Компрометация службы в таком случае приводит к получению сторонним кодом высокоуровневых привилегий. В идеале служба должна иметь минимум необходимых привилегий, достаточных для выполнения ее задач. В новых версиях Windows появилась возможность ограничить количество привилегий, которые получит служба при запуске. Справедливости ради стоит отметить, что ограничить набор привилегий для служб можно было и раньше, до Windows Vista, однако для этого требуется несколько больше усилий. Кроме того, в новых операционных системах эта возможность применима не только к доменным пользователям, но и к системным учетным записям: LocalService, NetworkService, LocalSystem.

Работает это следующим образом.

При запуске обычной службы диспетчер управления службами (SCM) проверяет, какие привилегии включены в маркере пользователя и какие необходимы службе. После этого лишние привилегии исключаются из маркера процесса службы.

При запуске процесса службы, содержащего много сервисов, например svchost, список назначаемых ей привилегий будет состоять из суммы всех необходимых привилегий для каждой службы, исполняемой в рамках процесса.

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

Если служба требует привилегию, которой нет в маркере процесса, то SCM не запустит ее. Например, процесс использует учетную запись NetworkService для работы, и при этом запрашивает для себя SeTcbPrivilege. Но учетная запись NetworkService не содержит SeTcbPrivilege, поэтому служба запущена не будет.

Для того чтобы настроить список привилегий для конкретной службы, можно воспользоваться утилитой sc.exe: sc <компьютер> privs <список привилегий>. В качестве списка привилегий принимается строка, в которой перечислены требуемые привилегии, разделенные знаком «/», например «SeBackupPrivilege/SeRestorePrivilege». Запросить привилегии, назначенные конкретной службе, можно, используя ту же утилиту: sc <компьютер> qprivs. С другой стороны, список привилегий хранится в реестре, в ключе HKLM\System\CurrentControlSet\Services параметр RequiredPrivilege.

SID для каждой службы

Существует много служб, требующих доступа к таким ресурсам, доступ к которым есть только у привилегированных учетных записей. В предыдущих версиях Windows эта проблема в основном решалась путем предоставления учетной записи сервиса повышенных прав доступа. Правда, и тогда была возможность раздавать права достаточно детально, однако это требовало довольно большой работы. Подход заключался в изучении ресурсов, к которым требовался доступ, и предоставлении учетной записи службы доступа к ним вручную. Но эта учетная запись, как и учетные записи других пользователей, требует придерживаться политики паролей и менять пароль периодически, что ведет за собой переконфигурирование всех служб, запущенных подобным способом. Кроме того, пароль учетной записи таких служб хранится в специальном ключе реестра и может быть извлечен оттуда довольно легко. Поэтому требовалось менять положение вещей.

В итоге в новых версиях операционных систем был создан механизм изоляции служб, позволяющий получать доступ к нужным ресурсам без необходимости создания и применения пользовательских учетных записей. К примеру, изоляция служб позволяет службам антивирусного ПО работать под учетной записью с меньшими, чем у LocalSystem, правами, но при этом получать доступ к нужным ресурсам.

Сервис использует личный SID, называемый per-service SID, для получения доступа к нужным ему ресурсам. После того как SID назначен службе, администратор может назначить права на соответствующие объекты этому SID, добавив его в нужные ACL. При этом назначенный SID будет добавлен к маркеру процесса службы. Если процесс содержит много служб, то все их SID будут добавлены к маркеру этого процесса.

Кроме того, при использовании данного механизма маркер процесса может быть помечен как ограниченный.

Ограниченный маркер процесса

Наличие своего SID у службы позволяет исключить запуск служб с повышенными правами. Однако это не мешает сервису обращаться к другим ресурсам, доступным для его учетной записи. Допустим, некий сервис запущен с учетной записью LocalService и включенным per-service SID. Эта служба будет иметь доступ не только к тем ресурсам, к которым он был явно назначен, но и к ресурсам, к которым есть доступ у учетной записи LocalService. В итоге в случае компрометации службы атакующий получит доступ к тем ресурсам, которые не относятся к атакованной службе.

Для решения этой проблемы в Windows Vista и более поздних версиях был введен механизм ограниченных маркеров процесса. Когда служба использует данный механизм, per-service SID добавляется в обычный список SID и в специальный — ограниченный список, в ограниченном маркере. В результате служба будет иметь доступ на запись только к тем объектам, у которых SID службы явно присутствует в списке разрешений. Правда, учитывая поведение мультисервисных процессов, в маркер процесса будут входить все службы, исполняемые в нем. Но даже это значительно ограничивает возможности, доступные скомпрометированным службам.

Утилита sc.exe имеет два новых параметра для работы с per-service SID. Параметр sidtype изменяет тип SID службы: sc <компьютер> sidtype [имя службы] [тип]. Тип может быть . Если данный параметр имеет значение unrestricted, диспетчер управления службами (SCM) добавит SID этой службы к маркеру процесса службы в следующий раз, когда этот процесс будет запущен при запуске первой из своих служб. Если данный параметр имеет значение restricted, диспетчер управления службами (SCM) добавит SID этой службы к маркеру процесса службы в следующий раз, когда процесс будет запущен при запуске первой из своих служб. Кроме того, SID данной службы будет добавлен к списку ограниченных SID в маркере процесса. Маркер процесса будет являться ограниченным маркером. Кроме того, если служба является участником разделяемого процесса, все службы, участвующие в этом процессе, должны иметь данный тип SID, чтобы описанные выше действия были выполнены. Если данный параметр имеет значение none, SCM не будет добавлять SID службы к маркеру процесса службы. Эти параметры нельзя применять к драйверам. Параметр qsidtype позволяет получить тип SID службы: sc <компьютер> qsidtype [имя службы]. Перечислить типы всех служб можно вот так:

cls
$serviceList = Get-Service
foreach ($service in $serviceList){
   $s = "sc.exe qsidtype "+$service.name
Invoke-Expression $
}

Еще один параметр утилиты sc.exe предназначен для получения SID службы: sc showsid [имя службы].

Изоляция нулевой сессии

Об этом нововведении написано уже очень много. Вкратце скажу, что в предыдущих версиях операционных систем первая пользовательская сессия в системе попадала в нулевую сессию. В эту же сессию попадали и службы. Это позволяло, к примеру, посылать оконные сообщения службам, чтобы атаковать их. В новых версиях нулевая сессия выделена исключительно для служб. В результате появились некоторые ограничения. Например, службы не могут отображать окна на рабочих столах пользователей; поскольку у нулевой сессии свой рабочий стол, окна будут отображены на нем и пользователь их не увидит. Кроме того, службы не могут посылать сообщения при помощи PostMessage или SendMessage. В свою очередь и службам не могут быть отправлены оконные сообщения.

Андрей Вернигора (eosfor@gmail.com) — администратор баз данных и системный администратор на одном из предприятий компании «Укртранснафта». Имеет сертификат MCP