Статья ASM. Демоны в Windows (2) – Integrity Control, или контроль целостности объектов

Бесконечные атаки и всевозможные взломы вынуждают Microsoft вводить всё более жёсткие квоты на использование системных ресурсов. Начиная с NT-4, каждое ядро несёт в себе что-то новое, а выделяется на этом фоне Vista NT-6. Не смотря на то, что век её был коротким, она принесла с собой много революционных идей, особенно в плане безопасности. Если на XP NT-5 мы могли с лёгкостью внедряться в системные процессы и переполнять их буферы в целях захвата власти, то на Win-7 сделать это уже не так просто. Одним из препятствий на пути становится "контроль целостности" защищённых объектов, о котором и пойдёт речь в данной части статьи.

Оглавление:


1. Введение
2. Токен и дескриптор безопасности
3. Устройство механизма "Mandatory Integrity Control"
4. Практика - список процессов и их уровня IL
5. Заключение



1. Введение

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

Проблема в том, что инженеры майков и рады-бы полностью запереть ядро на большой замок, но вот несколько его "воинов" остались в тылу врага на пользовательской территории, а значит ядру нужно как-то поддерживать с ними связь. В качестве примера можно привести такие системные файлы как: csrss.exe (подсистема клиент-сервера), winlogon, и explorer.exe. Большая ставка делалась на мобилизацию всей системной кухни из пользовательского пространства в специально отведённый для этих целей изолированный сеанс(0) – теперь все системные файлы и службы (кроме перечисленных выше) никак не пересекаются с юзерскими. Нужно сказать, что это было лучшим из возможных решений.

После того-как неугомонные хакеры нашли дыры в нулевом сеансе и опять повеяло сквозняком, инженерам пришлось искать новые меры безопасности и ограничивать доступ к объектам системы дополнительными средствами. Одним из таких средств и стал "Integrity Control", что на исконно русском звучит как контроль целостности. Если рассматривать грубо, то на данный момент дела в подсистеме безопасности обстоят так..


2. Токен пользователя, и дескриптор безопасности объекта

1. При входе в систему мы сразу упираемся в таможенную зону Winlogon, где входящие в состав Lsass.exe процедуры вручают нам мандат пребывания на территории, в виде структуры "TOKEN". Этот токен нужно воспринимать как цифровой паспорт пользователя, внутри которого (помимо прочего) хранятся:


• наши привилегии в системе,
• отметки о раcсовой принадлежности к какой-либо группе,
• массив идентификаторов SID "Security Identifier".

Подсистема сервера проверки подлинности Lsass.exe (Local Security Authority SubSystem) назначает каждому пользователю не один, а макс.16 различных идентификаторов SID, каждый из которых несёт в себе определённую инфу. Чтобы ознакомиться с основными свойствами вашего токена и списком его SID, можно в ком.строке ввести команду: whoami /all /fo list. Лично у себя я насчитал 13 идентификаторов, с полным их описанием.

C этого момента, при доступе к защищённым объектам системы, мы должны будем предъявлять данный токен системным сторожам, на основании чего они решат, дать нам запрашиваемый доступ, или нет. Проверки осуществляются только сопоставлением SID.

2. За некоторым исключением, почти все объекты Win являются защищаемыми. К ним относятся: файл\каталог, процесс\поток, порт\устройство, расшаренные принтеры, именованные каналы Pipe, всевозможная мелочь типа семафоры, эвенты, мутанты, таймеры и прочее. С полным списком можно ознакомиться в программе WinObj из пакета . Отметим, что если жёсткий диск отформатирован в FAT-32, то все файлы (включая системные из папки Windows) теряют защитную оболочку, и доступ к ним сможет получить любой из пользователей.

Чтобы защитить объект, система привязывает к нему дескриптор безопасности SD. У каждого объекта свой дескриптор, а прочитать и модифицировать его можно функциями Get\SetSecurityInfo(), предварительно открыв через CreateFile(). На физ.уровне SD представляет собой одноимённую структуру в памяти SECURITY_DESCRIPTOR, о которой прекрасно осведомлён ядерный отладчик WinDbg. Указатель на дескриптор безопасности прописан в структуре заголовка объекта OBJECT_HEADER:


C-подобный:
lkd> dt _security_descriptor
;//--------------------------------
nt!_SECURITY_DESCRIPTOR
   +0x000 Revision         : UChar         ;// ревизия структуры (всегда =1)
   +0x001 Sbz1             : UChar         ;// резерв (байт выравнивания на 16-бит)
   +0x002 Control          : Uint2B        ;// свойства дескриптора SD
   +0x004 Owner            : Ptr32 Void    ;// линк на SID владельца объекта
   +0x008 Group            : Ptr32 Void    ;// линк на SID группы, в которую входит владелец
   +0x00c Sacl             : Ptr32 _ACL    ;// линк на список SACL
   +0x010 Dacl             : Ptr32 _ACL    ;// линк на список DACL

Значит структура начинается с информации о владельце объекта – это поля Owner, и Group. Далее идут два указателя на списки ACL (Access Control List, список контроля доступа), которые бывают двух видов – DACL (Discretionary, дискреционный, избирательный), и SACL (системный). Непосредственно атрибуты защиты объекта хранятся в его списке DACL, а второй SACL был введён лишь для аудита, т.е. для отслеживания несанкционированных обращений к объекту, с последующей записью их в лог. Два этих списка являются родственными душами, поэтому структуры у них одинаковы:

C-подобный:
lkd> dt _acl
;//--------------------------------
nt!_ACL
   +0x000 AclRevision      : UChar
   +0x001 Sbz1             : UChar
   +0x002 AclSize          : Uint2B   ;// общий размер списка ACL
   +0x004 AceCount         : Uint2B   ;// кол-во записей ACЕ в нём
   +0x006 Sbz2             : Uint2B

Структуры ACL – это лишь заголовки списков DACL и SACL, а сами-же списки организованы в виде записей ACE (Access Control Entry). Кол-во таких записей в каждом из списков указывается в поле "AceCount" его заголовка. В записях ACE хранится информация о доверенных лицах в системе, которым разрешён/запрещён доступ к данному объекту. Для DACL часто используются всего два типа ACE:

• ACCESS_ALLOWED_ACE – запись описывает разрешения доступа,
• ACCESS_DENIED_ACE – запись запрещений доступа.

C-подобный:
lkd> dt _access_allowed_ace –b
;//--------------------------------
uxtheme!_ACCESS_ALLOWED_ACE
   +0x000 Header           : _ACE_HEADER
      +0x000 AceType          : UChar
      +0x001 AceFlags         : UChar
      +0x002 AceSize          : Uint2B
   +0x004 Mask             : Uint4B
   +0x008 SidStart         : Uint4B

ACCESS_ALLOWED_ACE через дворд "Mask" предписывает, что именно разрешено делать обладателю данного SID при доступе к объекту. Соответственно если тип указывается как DENIED_ACE, то запись характеризует запрещения доступа. Ниже представлена битовая карта поля "Mask":

AccessMask.png


pExt.png

thExt.png

tokExt.png


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

Для визуального просмотра подноготной имеет смысл воспользоваться отладчиком – мы можем запросить дескриптор безопасности SD как своего\любого процесса, так и отдельно взятого системного объекта. Если планируем освятить объект, сначала нужно получить к нему доступ через расширение !handle, которое возвращает хэндлы всех открытых на данный момент объектов. Но я хочу изъять детали дескриптора своего процесса SecurDesc.exe, для чего запустив его на исполнение буду преследовать следующий алго:


C-подобный:
;//--- Запрашиваю адрес своего процесса --------------------
lkd> !process 0 0 SecurDesc.exe

PROCESS 89b8d248  SessionId: 1  Cid: 0b48    Peb: 7ffdf000  ParentCid: 0748
    DirBase: 5fe8d980  ObjectTable: a5b47e50  HandleCount: 134.
    Image  : SecurDesc.EXE

;//--- Получаю указатель на заголовок его объекта ----------
lkd> !object 89b8d248

Object: 89b8d248  Type: (847cfe38) Process
    ObjectHeader: 89b8d230 (new version)
    HandleCount: 5  PointerCount: 24

;//--- Линк на "SecurityDescriptor" лежит в заголовке +14h ------
lkd> dt _object_header 89b8d230

nt!_OBJECT_HEADER
   +0x000 PointerCount       : 0n24
   +0x004 HandleCount        : 0n5
   +0x004 NextToFree         : 0x00000005 Void
   +0x008 Lock               : _EX_PUSH_LOCK
   +0x00c TypeIndex          : 0x7 ''
   +0x00d TraceFlags         : 0 ''
   +0x00e InfoMask           : 0x8 ''
   +0x00f Flags              : 0 ''
   +0x010 ObjectCreateInfo   : 0x864dd940 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged  : 0x864dd940 Void
   +0x014 SecurityDescriptor : 0x9a9576f7 Void  ;//<--- Дескриптор безопастности!
   +0x018 Body               : _QUAD

;//--- Рсширение !sd выводит детали дескриптора ------------
;//--- Внимание! Нужно сбросить 3-мл.бита адреса -----------

lkd> !sd 0x9a9576f0 1
->Revision: 0x1
->Sbz1    : 0x0
->Control : 0x8814
            SE_DACL_PRESENT
            SE_SACL_PRESENT
            SE_SACL_AUTO_INHERITED
            SE_SELF_RELATIVE
->Owner   : S-1-5-32-544                  (Alias: BUILTIN\Администраторы)
->Group   : S-1-5-21-1365493694-xx-xx-513 (Group: G31TM-P21\None)

->Dacl    :
->Dacl    : ->AclRevision: 0x2
->Dacl    : ->Sbz1       : 0x0
->Dacl    : ->AclSize    : 0x50
->Dacl    : ->AceCount   : 0x3
->Dacl    : ->Sbz2       : 0x0

->Dacl    : ->Ace[0]: ->AceType : ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[0]: ->AceFlags: 0x0
->Dacl    : ->Ace[0]: ->AceSize : 0x18
->Dacl    : ->Ace[0]: ->Mask    : 0x001fffff
->Dacl    : ->Ace[0]: ->SID     : S-1-5-32-544 (Alias: BUILTIN\Администраторы)

->Dacl    : ->Ace[1]: ->AceType : ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[1]: ->AceFlags: 0x0
->Dacl    : ->Ace[1]: ->AceSize : 0x14
->Dacl    : ->Ace[1]: ->Mask    : 0x001fffff
->Dacl    : ->Ace[1]: ->SID     : S-1-5-18 (Well Known Group: NT AUTHORITY\система)

->Dacl    : ->Ace[2]: ->AceType : ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[2]: ->AceFlags: 0x0
->Dacl    : ->Ace[2]: ->AceSize : 0x1c
->Dacl    : ->Ace[2]: ->Mask    : 0x00121411
->Dacl    : ->Ace[2]: ->SID     : S-1-5-5-0-180542 (no name mapped)

->Sacl    :
->Sacl    : ->AclRevision: 0x2
->Sacl    : ->Sbz1       : 0x0
->Sacl    : ->AclSize    : 0x1c
->Sacl    : ->AceCount   : 0x1
->Sacl    : ->Sbz2       : 0x0

->Sacl    : ->Ace[0]: ->AceType : SYSTEM_MANDATORY_LABEL_ACE_TYPE
->Sacl    : ->Ace[0]: ->AceFlags: 0x0
->Sacl    : ->Ace[0]: ->AceSize : 0x14
->Sacl    : ->Ace[0]: ->Mask    : 0x00000003
->Sacl    : ->Ace[0]: ->SID     : S-1-16-12288 (Label: Mandatory Label\High Mandatory Level)

Так мы получили свойства дескриптора безопасности своего процесса где видно, что его владельцем "Owner" является администратор, а в списке доступа DACL имеется всего три записи АСЕ. Первая с маской "Полный доступ" = 0x001fffff описывает разрешения "Allowed" для пользователей из группы админы, вторая принадлежит юзеру SYSTEM, а третья (с маской немного ограниченных прав 0x00121411) отведена для пользователя текущей сессии, о чём свидетельствует её сессионный SID = S-1-5-5-0-xxx.

В штатной библиотеке Win Advapi32.dll имеется огромное кол-во функций, с помощью которых можно легко модифицировать записи АСЕ. Множество примеров их использования приводится в книге . То-есть по неизвестной причине Microsoft предоставила полный карт-бланш (неограниченные полномочия) любому пользователю, включая обычных юзверей – достаточно запросить привилегию SE_SECURITY_NAME, после чего использовать функции из класса SetSecurityDescriptorXX().

В качестве разминки посмотрим на ConvertSecurityDescriptorToStringSecurityDescriptor(), которая извлекает маску защиты объекта из списка DACL. Эта функция возвращает маску в виде текстовой строки на языке SDDL (Security Descriptor Definition Language). Полученную строку можно заточить под свои нужны, перевести опять в бин чз ConvertStringSecurityDescriptorToSecurityDescriptor(), и запихать её обратно в дескриптор при помощи, например, SetSecurityInfo(). Вот пример извлечения строки DACL:


C-подобный:
format   pe console
include 'win32ax.inc'
entry    start
;//----------
pDacl           dd  0
pDesc           dd  0
align 16
buff            db  0
;//----------
.code
start:   invoke  SetConsoleTitle,<'*** Security Desc Info ***',0>

;//----- Запрашиваем дескриптор SD своего процесса --------------
         invoke  GetCurrentProcess
         invoke  GetSecurityInfo,eax,\
                                 SE_KERNEL_OBJECT,\
                                 DACL_SECURITY_INFO,\
                                 0,0,pDacl,0,pDesc

;//----- Переводим его свойства в строку SDDL -------------------
         invoke  ConvertSecurityDescriptorToStringSecurityDescriptor,\
                                 [pDesc],1,\
                                 DACL_SECURITY_INFO,\
                                 buff,0
        cinvoke  printf,<10,' Current process DACL string:',10,10,' %s',0>,dword[buff]

@exit:  cinvoke  _getch     ;// клавиша
        cinvoke  exit,0     ;// выход!
;//----------
section '.idata' import data readable
library  msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',advapi32,'advapi32.dll'
include  'api\msvcrt.inc'
include  'api\kernel32.inc'
include  'api\advapi32.inc'
include  'equates\advapi32.inc'

Dacl_string.png


В скрепке лежит инклуд Advapi32.inc, где можно найти полное описание литеров строк SDDL.
Каждый АСЕ заключается в скобки, а элементы записи в ней отделены точкой с запятой. Таким образом, мы видим здесь строки трёх записей АСЕ, где представлены их тип (А, Allowed), дворд с НЕХ-маской, а так-же SID пользователей, которым принадлежит запись: BA\SY\S-1-5-5-0-xx. Чтобы получить доступ к данному объекту, достаточно изменить SID любой из записей например на "AU" (Authenticated Users, все зареганные), или "BU" (BuiltIn Users, юзеры). Можно пойти по обратному пути, и аналогичным образом наоборот поднять статус своего процесса до админа "ВА".


3. Устройство механизма "Mandatory Integrity Control"

Но такую картину мы могли наблюдать только на системах ХР с ядром NT-5.
Чтобы покончить с этим беспределом, начиная с Висты продуманы Microsoft ввели доп.уровень проверок доступа под названием MIC, или "Обязательный контроль целостности", что на англ.манер звучит как "Mandatory Integrity Control". Теперь доступ к объектам проверяется не только посредством записей АСЕ в списках DACL, но и записью типа SYSTEM_MANDATORY_LABEL в списке SACL. Как видим, запись данного типа присутствует в дескрипторе безопасности выше, и имеет следующий вид:


C-подобный:
->Sacl    :
->Sacl    : ->AclRevision: 0x2
->Sacl    : ->Sbz1       : 0x0
->Sacl    : ->AclSize    : 0x1c
->Sacl    : ->AceCount   : 0x1
->Sacl    : ->Sbz2       : 0x0

->Sacl    : ->Ace[0]: ->AceType : SYSTEM_MANDATORY_LABEL_ACE_TYPE
->Sacl    : ->Ace[0]: ->AceFlags: 0x0
->Sacl    : ->Ace[0]: ->AceSize : 0x14
->Sacl    : ->Ace[0]: ->Mask    : 0x00000003
->Sacl    : ->Ace[0]: ->SID     : S-1-16-12288 (Label: Mandatory Label\High Mandatory Level)

Здесь имеется маска(3), которая принадлежит пользователю с SID = S-1-16-12288. Идентификатор с данным значением и представляет собой уровень целостности данного объекта "Integrity Level". Он не оставляет пространства для разговора со-своей тушкой всем пользователям, уровень которых ниже этого значения. В отличии от DACL, стойкие ноты записей АСЕ в системных списках SACL подменить довольно сложно, хотя и тут имеется своя брешь. Давайте разберём устройство этого механизма, чтобы определить, в какую сторону вообще нужно копать при попытках доступа к защищённым объектам Win7+.

На данный момент, все современные системы поддерживают 7 уровней целостности объектов, константы которых увеличиваются с шагом 0x1000. Для обозначения уровней "Integrity Level", система выделяет SID с начальным значением S-1-16-xx, где последнее число(хх) представляется константой уровня в 10-тичном виде. Например 0х1000 равно S-1-16-4096, 0х2000 = 8192, и т.д. В табличке ниже перечислены все возможные уровни IL с кратким описанием их владельцев:


SID-desc.png


Как мы уже знаем, у любых объектов имеется владелец Owner, а в свою очередь владелец имеет свой токен и SID. Процессы могут получать доступ на запись только к тем объектам, уровень IL которых меньше или равно. Вообще-то словосочетание "уровень целостности" не совсем подходит для данного механизма – просто воспринимайте его как "уровень доверия" объекта, к вызывающему субъекту. То-есть объекты не доверяют процессам, если их уровень ниже его\собственного. С введением этого механизма, огромная армия малвари отправилась на свалку истории, освободив нишу для новых идей.

В системе имеется монитор ссылок SRM "Security Reference Monitor". Когда процесс ссылается на объект, именно SRM решает, следует-ли предоставить данному процессу права доступа к объекту. Это делается путём сравнения прикреплённого к процессу токена, со-списком управления доступом к объекту DACL. Монитор сравнивает идентификаторы безопасности SID в записи DACL, с SID в токене пользователя, чтобы определить, какой уровень доступа должен быть предоставлен процессу. Если какой-либо из SID в DACL отказывает в доступе, запрос процесса отвергается с сообщением об ошибке ACCESS_DENIED.

На рисунке ниже представлена обобщённая схема механизма MIC.
Зелёные блоки здесь обозначают токены пользователей, а синие – порождаемые ими процессы. Поскольку объекты типа Process наследуют права своих родителей, их дескрипторы безопасности SD получают уровни целостности владельцев. Когда левый процесс пытается получить доступ к правому\системному процессу, монитор ссылок берёт уровень IL из токена, и сверяет его с уровнем в дескрипторе безопасности объекта. В данном случае IL в токене вызывающего субъекта меньше, поэтому доступ не предоставляется! Однако если системный процесс запросит запись в адресное пространство пользовательского процесса, монитор SRM не станет возражать, т.к. судя по уровню "IntegrityLevel" он является доверенным:


MIC.png


Найти значения уровней целостности "IntegrityLevel" в токене не так просто, как может показаться на первый взгляд. Они зарыты глубоко, хотя ссылки на них лежат на поверхности. Выше уже упоминалось, что подсистема безопасности Lsass.exe назначает каждому пользователя не один, а сразу несколько идентификаторов SID (см.whoami в консоли), среди которых имеется и SID уровня целостности. Дело в том, что в токене лежит лишь указатель на массив идентификаторов, а индекс SID-IL в этом массиве представлен полем "IntegrityLevelIndex". Проведём такой эксперимент в отладчике WinDbg..

C-подобный:
;//---->> Запустим свой процесс, и запросим карту всех\активных процессов
lkd> !process 0 0

**** NT ACTIVE PROCESS DUMP ****
PROCESS 8a000030  SessionId: 1  Cid: 0e90    Peb: 7ffd3000  ParentCid: 0ed0
    DirBase: 5fea7cc0   ObjectTable: 9bda1878  HandleCount: 41.
    Image  : SecurInfo.EXE

;//---->> Находим среди них свой, и запрашиваем его детали
lkd> !process 8a000030 1

PROCESS 8a000030  SessionId: 1  Cid: 0e90    Peb: 7ffd3000  ParentCid: 0ed0
    DirBase  : 5fea7cc0  ObjectTable: 9bda1878  HandleCount:  40.
    Image    : SecurInfo.EXE
    VadRoot  : 8acd94d0 Vads 25 Clone 0 Private 66. Modified 0. Locked 0.
    DeviceMap: 86aa5140
    Token    : a6eca0f0

;//---->> Имеем адрес своего токена – посмотрим на его структуру
lkd> dt _token a6eca0f0

nt!_TOKEN
   +0x000 TokenSource         : _TOKEN_SOURCE
   +0x040 Privileges          : _SEP_TOKEN_PRIVILEGES
   +0x074 SessionId           : 1
   +0x078 UserAndGroupCount   : 0xf
   +0x08c DefaultOwnerIndex   : 4
   +0x090 UserAndGroups       : 0xa6eca2d0 _SID_AND_ATTRIBUTES
   +0x094 RestrictedSids      : (null)
   +0x0a4 TokenType           : 1 ( TokenPrimary )
   +0x0b4 IntegrityLevelIndex : 0xe
   +0x0b8 MandatoryPolicy     : 3

На массив идентификаторов SID указывает здесь поле "UserAndGroups" со-значением 0xA6ECA2D0, каждая запись в котором представляется структурой "SID_AND_ATTRIBUTES". Общее кол-во записей в массиве хранится в поле "UserAndGroupCount" и в данном случае это 0x0F=16 структур в массиве. В свою очередь, индекс SID уровня целостности нашего процесса в этом массиве, лежит в поле "IntegrityLevelIndex", и равен 0x0E=14. Теперь можно запросить массив идентификаторов, и найти в нём SID-IL:

IL_Sid.png


Ещё одним немаловажным моментом является введение обязательных политик доступа "Mandatory Policy", которые тесно связаны с уровнями целостности объектов. Если посмотреть на содержимое токена выше, по смещению 0xb8 можно обнаружить в нём одноимённое поле со-значением(3). В сишном хидере Winnt.h имеются константы с описанием данных политик где видно, что для доступа к защищённым объектам нам явным образом мешает политика(1) "NO_WRITE_UP" – проблема решается сбросом этого значения в нуль:

C-подобный:
TOKEN_MANDATORY_POLICY_OFF              =  0x0   ;// Руль! Для токена не применяется обязательная политика целостности.
TOKEN_MANDATORY_POLICY_NO_WRITE_UP      =  0x1   ;// Процесс не может выполнять запись в объекты с более высоким уровнем.
TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN  =  0x2   ;// Уровень, который является меньшим из уровня родителя и уровня исполняемого файла.
TOKEN_MANDATORY_POLICY_VALID_MASK       =  0x3   ;// POLICY_NO_WRITE_UP + POLICY_NEW_PROCESS_MIN


4. Практика – список активных процессов, и уровни их целостности

В практической части попробуем запросить уровни целостности всех активных процессов. Значит сначала создаём цикл при помощи функций CreateToolhelp32Snapshot() + Process32Next(), которые перечислят все процессы как диспетчер задач Win. Теперь внутри цикла открываем найденный процесс через OpenProcess(), и запрашиваем его токен OpenProcessToken(). Получив дескриптор токена, вызываем функцию GetTokenInformation(), передав ей параметр "TokenIntegrityLevel". Так мы получим SID уроня целостности процесса, и остаётся обозначить его строкой через LookupAccountSid(). Здесь нужно отметить, что для доступа к системным процессам, необходимо обзавестись привилегией отладки SE_DEBUG.

Функция GetTokenInformation() способна вытащить из токена огромное кол-во информации, в зависимости от одного из 48 передаваемых ей параметров. Список этих параметров спрятан в спойлере ниже, а нужный нам числи в розысках под номером 25:

C-подобный:
;//--- Класс запросов для Set/Get TokenInformation() -----
;// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_information_class

TokenUser                    =  1    ;// SID пользователя (атрибуты не определены)
TokenGroups                  =  2    ;// массив SID групп (и их атрибуты)
TokenPrivileges              =  3    ;// массив LUID привилегий (и их атрибуты)
TokenOwner                   =  4    ;// владелец
TokenPrimaryGroup            =  5    ;// группа пользователя токена
TokenDefaultDacl             =  6    ;// DACL, который будет назначен всем объектам, использующим этот токен
TokenSource                  =  7    ;// текстовый (и числовой) ID создателя токена
TokenType                    =  8    ;// тип
TokenImpersonationLevel      =  9    ;// уровень олицетворения
TokenStatistics              =  10   ;// общая информация о текене
TokenRestrictedSids          =  11   ;// ограниченный SID
TokenSessionId               =  12   ;// SID сессии Logon
TokenGroupsAndPrivileges     =  13 
TokenSessionReference        =  14
TokenSandBoxInert            =  15
TokenAuditPolicy             =  16
TokenOrigin                  =  17
TokenElevationType           =  18
TokenLinkedToken             =  19
TokenElevation               =  20
TokenHasRestrictions         =  21
TokenAccessInformation       =  22
TokenVirtualizationAllowed   =  23
TokenVirtualizationEnabled   =  24
TokenIntegrityLevel          =  25    ;// SID уровня целостности
TokenUIAccess                =  26    ;// Уровень целостности: S-1-16-8208
TokenMandatoryPolicy         =  27
TokenLogonSid                =  28
TokenIsAppContainer          =  29
TokenCapabilities            =  30
TokenAppContainerSid         =  31
TokenAppContainerNumber      =  32
TokenUserClaimAttributes     =  33
TokenDeviceClaimAttributes   =  34
TokenRestrictedUserClaimAttributes    =  35
TokenRestrictedDeviceClaimAttributes  =  36
TokenDeviceGroups            =  37
TokenRestrictedDeviceGroups  =  38
TokenSecurityAttributes      =  39
TokenIsRestricted            =  40
TokenProcessTrustLevel       =  41
TokenPrivateNameSpace        =  42
TokenSingletonAttributes     =  43
TokenBnoIsolation            =  44
TokenChildProcessFlags       =  45
TokenIsLessPrivilegedAppContainer  =  46
TokenIsSandboxed             =  47
MaxTokenInfoClass            =  48

C-подобный:
format   pe console
include 'win32ax.inc'
entry    start
;//----------
.data
pe32            PROCESSENTRY32

;//---- Структура "TOKEN_PRIVILEGES"
align 16
newState:
PrivilegeCount  dd  1
Luid1           dq  0
Attribute1      dd  SE_PRIVILEGE_ENABLED

sidStr          rb  128
Name            rb  128
DomainName      rb  128
cbName          dd  0
cbDomainName    dd  0
peUse           dd  0

hToken          dd  0
hSnap           dd  0
pcbBytesNeeded  dd  0

align 16
buff            db  0
;//----------
.code
proc  GetIntegrityLevel      ;//<--- Процедура запроса уровня целостности
         mov     edi,Name         ;// Очистить буфер для строки
         mov     ecx,128/4
         xor     eax,eax
         rep     stosd
         invoke  GetTokenInformation,[hToken],\
                                     TokenIntegrityLevel,\
                                     buff,32,pcbBytesNeeded
         mov     esi,dword[buff]
         push    esi
         invoke  ConvertSidToStringSid,esi,sidStr
         pop     esi
         invoke  LookupAccountSid,0,esi,\
                                  0,cbName,\
                                  0,cbDomainName,peUse
         invoke  LookupAccountSid,0,esi,\
                                  Name,cbName,\
                                  DomainName,cbDomainName,peUse
         invoke  CharToOem,Name,Name
        cinvoke  printf,<'   %-13s  %s',10,0>, dword[sidStr],Name
@@:      ret
endp
;//*********************************************************

start:   invoke  SetConsoleTitle,<'*** Process Integrity Level ***',0>

;//----- Выставляем привилегию "SeDebug" в своём токене!
         invoke  GetCurrentProcess
         invoke  OpenProcessToken,eax,\
                                  TOKEN_QUERY + TOKEN_ADJUST_PRIVILEGES,hToken
         invoke  LookupPrivilegeValue,0,<'SeDebugPrivilege',0>,Luid1
         invoke  AdjustTokenPrivileges,[hToken],0,newState,0,0,0
         or      eax,eax
         jnz     @f
        cinvoke  printf,<10,' SeDebugPrivilege error!',0>
         jmp     @exit
@@:      invoke  CloseHandle,[hToken]

;//***********************************************
        cinvoke  printf,<10,' Process                       PID    Hndl   Integrity Level',\
                         10,' --------------------------   ----    ----   -----------------------------',10,0>

;//----- Обход всех активных процессов ------------------------
         invoke  CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
         mov     [hSnap],eax
         invoke  Process32First,[hSnap],pe32
@next:   invoke  Process32Next,[hSnap],pe32     ;// EAX=0: ошибка
         or      eax,eax
         je      @stop
         mov     eax,[pe32.th32ProcessID]
         invoke  OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION, TRUE, eax
         push    eax eax
         mov     esi,pe32
         add     esi,PROCESSENTRY32.szExeFile
        cinvoke  printf,<' %-27s  %4d    %04x',0>,\
                         esi,[pe32.th32ProcessID],eax
         pop     eax
         invoke  OpenProcessToken,eax,TOKEN_QUERY,hToken
         call    GetIntegrityLevel
         pop     eax
         invoke  CloseHandle,eax
         jmp     @next

@stop:   invoke  CloseHandle,[hSnap]

@exit:  cinvoke  _getch     ;// клавиша
        cinvoke  exit,0     ;// выход!
;//----------
section '.idata' import data readable
library  msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',\
         user32,'user32.dll',advapi32,'advapi32.dll'
include  'api\msvcrt.inc'
include  'api\kernel32.inc'
include  'api\user32.inc'
include  'api\advapi32.inc'
include  'equates\advapi32.inc'

Result.png


Рассмотрим бегло этот скрин..
Обратите внимание на дескрипторы Handle процессов – их значение увеличивается на 8-байт. Это потому, что при запуске процесса на исполнение, система создаёт в его окружении "таблицу дескрипторов", куда помещает все открытые данным процессом хэндлы. На самом деле эти значения являются просто индексами в таблице, где лежат указатели на непосредственно дескрипторы. Когда я делал этот скрин, то не закрывал открытые процессы через CloseHandle(). Другой пример лежит в скрепке, где дескрипторы прихлопываются, и соответственно индекс не увеличивается, а просто перезаписывается в одном поле таблицы, с одинаковым значением.

Далее видим идентификаторы SID уровней целостности "IntegrityLevel", с привязанными к ним пояснительными строками. У всех системных процессов он равен 0х4000=16384, а у тех, что крышует админ 0х3000=12288 High. По этой причине, мои процессы не смогут получить доступ на запись к системным процессам.

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


5. Заключение

Эксперименты в отладчике и ручной поиск всевозможных полей в системных структурах, открывает двери в шелл-кодинг. Ведь хорошо известно, что в этой области программирования мы лишены возможности использовать функции Win32-API, и всё приходится делать ручками и головой. Именно поэтому я уделил большую часть топика логам дебагера. Как показали опыты, системы Виста+ это далеко не дырявая ХР, и инженеры майков потрудились на славу, чтобы оградить нас от нечисти. Они предложили нам вполне комфортную подушку безопасности, которую мы всё-таки попытаемся "проткнуть шилом" в следующей части статьи.

Уже по привычке, в скрепку кладу два представленных здесь исполняемых файла для тестов,
а так-же инклуд Advapi32.inc для тех, кто захочет сам собрать код из исходников. Всем удачи и пока!
 

Вложения

  • Mandatory Control.zip
    15,9 КБ · Просмотры: 238

hoka

One Level
02.06.2019
8
1
BIT
78
Взял на вооружение фразу: Человек любопытен по своей природе. Чем больше Microsoft прячет от нас детали реализации своих механизмов, тем больший интерес они возбуждают.
Спасибо за статью)
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!