• XSS.stack #1 – первый литературный журнал от юзеров форума

[ЗАМЕТКА] Ищем вхождения MmPteBase в ntoskrnl.exe при помощи IDAPython

varwar

El Diff
Забанен
Регистрация
12.11.2020
Сообщения
1 383
Решения
5
Реакции
1 537
Пожалуйста, обратите внимание, что пользователь заблокирован
Введение

В Windows 10 1607 (RS1) была добавлена рандомизация PTE, что усложнило манипуляции с их свойствами, описываемыми структурами _MMPTE и _MMPTE_HARDWARE для обхода SMEP через обнуление 63 бита - NoExecute.
Код:
3: kd> dt nt!_mmpte u.Hard.
   +0x000 u       :
      +0x000 Hard    :
         +0x000 Valid   : Pos 0, 1 Bit
         +0x000 Dirty1  : Pos 1, 1 Bit
         +0x000 Owner   : Pos 2, 1 Bit
         +0x000 WriteThrough : Pos 3, 1 Bit
         +0x000 CacheDisable : Pos 4, 1 Bit
         +0x000 Accessed : Pos 5, 1 Bit
         +0x000 Dirty   : Pos 6, 1 Bit
         +0x000 LargePage : Pos 7, 1 Bit
         +0x000 Global  : Pos 8, 1 Bit
         +0x000 CopyOnWrite : Pos 9, 1 Bit
         +0x000 Unused  : Pos 10, 1 Bit
         +0x000 Write   : Pos 11, 1 Bit
         +0x000 PageFrameNumber : Pos 12, 36 Bits
         +0x000 ReservedForHardware : Pos 48, 4 Bits
         +0x000 ReservedForSoftware : Pos 52, 4 Bits
         +0x000 WsleAge : Pos 56, 4 Bits
         +0x000 WsleProtection : Pos 60, 3 Bits
         +0x000 NoExecute : Pos 63, 1 Bit

Ранее база PTE была статичной и хранилась в константе MmPteBase. Собственно, она и сейчас используется во множестве функций ядра с той лишь разницей, что ее значение изменяется при каждом запуске ОС.

Код:
3: kd> x nt!MmPteBase
fffff803`2cefb358 nt!MmPteBase = <no type information>
3: kd> dps fffff803`2cefb358
fffff803`2cefb358  fffff880`00000000

В современных техниках эксплуатации ядра используется утечка этой константы при наличии примитива на чтение минимум 5 байт. Почему достаточно лишь пяти, ведь адрес в 64-битной системе имеет размер 64 бита? В действительности для большинства систем будет справедливо использование модели памяти PML4, которая описывает виртуальный адрес 48 битами.

11.png


В различных блогах при разработке эксплойта используется чтение значения вышеупомянутой константы MmPteBase по смещению MiGetPteAddress+0x13.

Код:
3: kd> dq nt!MiGetPteAddress+0x13
fffff803`2c51e4c3  fffff880`00000000 cccccccc`c3c10348
fffff803`2c51e4d3  cccccccc`cccccccc ca8b4ccc`cccccccc
fffff803`2c51e4e3  000fffff`ffffb848 d18b4cc8`234c0000

Сама функция состоит из одного базового блока и вычисляет PTE, где в качестве параметра передается VA.
12.png


На python эта функция могла бы выглядеть следующим образом:

Python:
def MiGetPteAddress(va):
    MmPteBase = 0xFFFFF88000000000
    return((va >> 9) & 0x7FFFFFFFF8) + MmPteBase

MiGetPteAddress(0xfffff8032c200000)

Цель

В какой-то момент мне стало интересно, а сколько таких смещений с MmPteBase присутствует в ядре? Зачем? Я предположил, что поиск таких смещений может быть полезен для написания стабильного эксплойта, т.к. в зависимости от версии ядра RVA могут различаться. Функция MiGetPteAddress находится в секции .text, достаточно близко к началу файла. Моя задача найти смещения как можно ближе к началу т.к. логично предположить, что в таком случае это и будут наиболее стабильные смещения.

До секции .text есть еще несколько, где потенциально могут находиться нужные данные. В конце мы проверим гипотезу, запустив скрипт на разных версиях ядра.

13.png


Пишем скрипт для IDAPython

Для поиска RVA я буду использовать IDA Pro и IDAPython.
Алгоритм был намечен следующий:

1. Объявить начало и конец файла
2. Объявить байтовый паттерн c учетом little-endian
3. Найти первое вхождение и вывести на экран VA и RVA.

Python:
pattern = '00 00 00 00 80 F6 FF FF' # little-endian
NtBase = ida_nalt.get_imagebase()
addr = idc.get_inf_attr(INF_MIN_EA)
for x in range(0, 1):
    addr = ida_search.find_binary(addr, idc.BADADDR, pattern, 16, ida_search.SEARCH_NEXT | ida_search.SEARCH_DOWN)
    if addr != idc.BADADDR:
        print("VA: 0x%x\t RVA: 0x%x\t" % (addr, (addr - NtBase)))

Запустив скрипт, в окне вывода мы можем видеть VA и RVA первого вхождения, которое используется функцией MiTrimWorkingSetBuildup.

Код:
VA: 0x140204ce7    RVA: 0x204ce7

Теперь сверимся с отладчиком. MmPteBase, которое в моем случае равно 0xfffff88000000000 находится там, где и должно. Напомню, из-за рандома при каждом новом запуске ОС это значение будет отличаться.

Код:
3: kd> dq fffff803`2c200000 + 0x204ce7
fffff803`2c404ce7  fffff880`00000000 48c93345`40668b4d
fffff803`2c404cf7  f000e481`4919e0c1 b94810e4`c149ffff

Сравниваем разные билды ntoskrnl.exe

У меня есть несколько версий баз с ntoskrnl.exe. Давайте запустим скрипт для каждой и проверим, имеют ли они общее RVA для MmPteBase.

Код:
ntoskrnl.exe_20h2_19042_572     VA: 0x140204ce7   RVA: 0x204ce7
ntoskrnl.exe_20h2_19042_685     VA: 0x1402038cd   RVA: 0x2038cd
ntoskrnl.exe_20h2_19042_746     VA: 0x1402038cd   RVA: 0x2038cd
ntoskrnl.exe_20h2_19042_867     VA: 0x1402038cd   RVA: 0x2038cd
ntoskrnl.exe_20h2_19042_906     VA: 0x1402038cd   RVA: 0x2038cd
ntoskrnl.exe_20h2_19042_928     VA: 0x1402038cd   RVA: 0x2038cd
ntoskrnl.exe_20h2_19042_985     VA: 0x140204c14   RVA: 0x204c14

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


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх