Московский физико-технический институт
Опубликован: 12.12.2007 | Доступ: свободный | Студентов: 5590 / 1909 | Оценка: 4.34 / 4.14 | Длительность: 13:57:00
ISBN: 978-5-94774-827-7
Лекция 14:

Структура системы защиты. Привилегии

< Лекция 13 || Лекция 14: 12 || Лекция 15 >

Управление привилегиями

Назначение и отзыв привилегий - прерогатива локального администратора безопасности LSA (Local Security Authority), поэтому, чтобы программно назначать и отзывать привилегии, необходимо применять функции LSA. Локальная политика безопасности системы означает наличие набора глобальных сведений о защите, например, о том, какие пользователи имеют право на доступ в систему, а также о том, какими они обладают правами. Поэтому говорят, что каждая система, в рамках которой действует совокупность пользователей, обладающих определенными привилегиями в отношении данной системы, является объектом политики безопасности. Объект политики используется для контроля базы данных LSA. Каждая система имеет только один объект политики, который создается администратором LSA во время загрузки и защищен от несанкционированного доступа со стороны приложений.

Использование функций LSA начинается с получения описателя объекта политики ( PolicyHandle ) при помощи функции LsaOpenPolicy, которая открывает описатель объекта на локальной или удаленной машине. Имя целевого компьютера передается функции в качестве одного из параметров. После завершения работы с объектом политики необходимо его закрыть, вызвав функцию LsaClose(PolicyHandle).

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

Задача перечисления привилегий учетной записи

Первая задача - перечисление привилегий данной учетной записи - решается при помощи функции LsaEnumerateAccountRights. Эта функция перечисляет привилегии пользователя с заданным идентификатором безопасности Sid в отношении системы с объектом политики PolicyHandle, передаваемыми ей в качестве параметров.

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

Прогон программы перечисления привилегий пользователя

В качестве примера рассмотрим программу, задача которой - вывод списка привилегий текущего пользователя.

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <stdio.h>
#include "ntsecapi.h"

BOOL GetUserSID(TOKEN_USER *, PDWORD pdwSize); 

void main(void){
 PSID pSid;
 DWORD TokenUserBufSize=256;
 TOKEN_USER *pUser;
 HANDLE hHeap;
 LSA_HANDLE hPolicy=NULL;
 LSA_OBJECT_ATTRIBUTES ObjAttributes = {0};
 ULONG Count = 0, i = 0, PrivDispBufLen = 512, Language = 0;
 PLSA_UNICODE_STRING Privileges = NULL; 
 WCHAR PrivBuf[512], PrivDispBuf[512];
 CHAR TempPrivDispBuf[512], TempPrivBuf[512];
 BOOL Return;

 hHeap = GetProcessHeap();
 pUser = (TOKEN_USER *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, TokenUserBufSize);
 if(!GetUserSID(pUser, &TokenUserBufSize)) printf("GetUserSid Error\n");
 pSid = pUser->User.Sid;  
 if(!IsValidSid(pSid)) { printf("Sid Error\n"); return; }
 
 ObjAttributes.Length = sizeof(ObjAttributes);
LsaOpenPolicy(NULL, &ObjAttributes, POLICY_VIEW_LOCAL_INFORMATION| POLICY_LOOKUP_NAMES| POLICY_CREATE_ACCOUNT, &hPolicy); 

 LsaEnumerateAccountRights(hPolicy, pSid, &Privileges, &Count);
     printf("Current user has %d privileges:\n",Count);  
 for(i = 0; i < Count; i ++) {
  lstrcpyn(PrivBuf, Privileges[i].Buffer, Privileges[i].Length);
                  PrivBuf[Privileges[i].Length] = 0;

  PrivDispBufLen = 512;
Return = LookupPrivilegeDisplayName(NULL, PrivBuf, PrivDispBuf, &PrivDispBufLen, &Language);
   if(!Return) lstrcpy(PrivDispBuf, TEXT("Дружественное имя привилегии не найдено"));
  
  CharToOem(PrivDispBuf, TempPrivDispBuf);
  CharToOem(PrivBuf, TempPrivBuf);
  printf("%s   (%s)\n", TempPrivBuf, TempPrivDispBuf);
 }
 
 if(Privileges) LsaFreeMemory(Privileges);
 LsaClose(hPolicy);
 HeapFree(hHeap,0,pUser);
}

BOOL GetUserSID(TOKEN_USER * pUser, PDWORD pdwSize) {
   BOOL   fSuccess = FALSE;
   HANDLE hToken   = NULL;
   DWORD dwSize;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))  return FALSE;
    if (!GetTokenInformation(hToken, TokenUser, pUser, *pdwSize, &dwSize))
	return FALSE;
    fSuccess = TRUE;
   if (hToken != NULL) CloseHandle(hToken);
   return(fSuccess);
}

Данная программа получает маркер доступа текущего процесса, извлекает из него Sid пользователя, при помощи функции LsaOpenPolicy открывает объект политики безопасности и вызывает функцию LsaEnumerateAccountRights для получения списка привилегий. Функция LookupPrivilegeDisplayName преобразует программное имя привилегии в дружественное имя. Для вывода имени привилегии на экран на русском языке используется функция CharToOem. Если число привилегий оказывается равным нулю, то с учетом замечания, сделанного выше, рекомендуется добавить пользователю, от имени которого запускается программа, одну или несколько привилегий с помощью административной консоли управления.

Добавление привилегий пользователю

Для назначения привилегий имеется функция LsaAddAccountsRights, а для отзыва привилегий - функция LsaRemoveAccountRights. Функция LsaAddAccountRights назначает одну или несколько привилегий учетной записи. Параметры повторяют параметры функции LsaEnumerateAccountRight, однако на этот раз структуру LSA_UNICODE_STRING, задающую привилегию, нужно сформировать явно. Например, если нужна привилегия завершения работы системы, это можно сделать следующим образом:

PLSA_UNICODE_STRING pUserRights;
PUserRights[0].Buffer = SE_SHUTDOWN_NAME;
PUserRights[0].Length = lstrlen(PUserRights[0].Buffer)+sizeof(WCHAR);
PUserRights[0].MaximumLength = PUserRights[0].Length + sizeof(WCHAR);

Написание, компиляция и прогон программы, позволяющей добавить пользователю одну или несколько привилегий

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

Заключение

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

< Лекция 13 || Лекция 14: 12 || Лекция 15 >
Ирина Оленина
Ирина Оленина
Николай Сергеев
Николай Сергеев

Здравствуйте! Интересует следующий момент. Как осуществляется контроль доступа по тому или иному адресу с точки зрения обработки процессом кода процесса. Насколько я понял, есть два способа: задание через атрибуты сегмента (чтение, запись, исполнение), либо через атрибуты PDE/PTE (чтение, запись). Но как следует из многочисленных источников, эти механизмы в ОС Windows почти не задействованы. Там ключевую роль играет менеджер памяти, задающий регионы, назначающий им атрибуты (PAGE_READWRITE, PAGE_READONLY, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_NOACCESS, PAGE_GUARD: их гораздо больше, чем можно было бы задать для сегмента памяти) и контролирующий доступ к этим регионам. Непонятно, на каком этапе может включаться в работу этот менеджер памяти? Поскольку процессор может встретить инструкцию: записать такие данные по такому адресу (даже, если этот адрес относится к региону, выделенному менеджером памяти с атрибутом, например, PAGE_READONLY) и ничего не мешает ему это выполнить. Таким образом, менеджер памяти остается в стороне не участвует в процессе...