EMET 4.0 и Windows Server 2012 R2

Всё про EMET 4.0 и его применение для Windows Server 2012 R2

Привет.

Вообще я уже много про EMET написал, но тема развивается, поэтому нужно актуализировать данные.

Плюс Андрей Бешков навёл меня тут на замечательный пост в /b двача Microsoft’а, в котором была предпринята попытка написать про преимущества mitigation tool’зов человеческим языком.

Вот такая вот:

Нормальная реакция на такую “крайне очевидную для любого читающего” табличку, в общем-то, выглядит именно так:

Да и количество с качеством материалов про всякие mitigation tools, в общем-то, крайне страдает – ощущение, что я один про EMET пишу вообще. Вот пример подобного – целый абзац про функционал всего продукта, плюс новое слово в безопасности – атаки класса Men-in-the-Middle (Мужик-Посередине).

Давайте разбираться, про что здесь речь. Для начала – убедимся, что на системе установлен .NET Framework 4 или выше и после установим стандартный бесплатный инструмент для управления защитными технологиями – Microsoft EMET 4.0. Некоторые базовые технологии можно настроить и без EMET – допустим, DEP – но нам нужен полный контроль.

Если у нас Windows 8 или Windows Server 2012, то не забудем установить вначале специальный патч – KB 2790907.

Стартовая оговорка – так как данные технологии интенсивно меняются, то речь будет идти про настройку оных для ядер NT 6.2 и выше (Windows 8 / Windows Server 2012). Все примеры в статье – с EMET 4.0 RTM и на Windows 8.1 RTM и Windows Server 2012 R2 RTM. Если хотите про настройки для устаревших ОС типа Windows XP и Windows Server 2003 – вам сюда, в статьи про старые версии EMET, там это есть. Эта статья не энциклопедия всего того, что было, а гайд для актуальных систем, нет смысла перегружать его дублирующейся информацией, которая есть в других статьях, да и информация эта особо не менялась – новых слов в защите Windows XP не сказано и не планируется. Пора уже закопать стюардессу, как говорилось в одном анекдоте.

EMET и встроенные защитные технологии NT 6.2

  • SEHOP и SafeSEH
  • ASLR
    • Работа ASLR Stack Randomization
    • Работа ASLR Heap Randomization
    • Работа ASLR Image Randomization
    • Работа ASLR Force image Randomization
    • Работа ASLR Bottom-up Randomization
    • Работа ASLR Top-down Randomization
    • Работа ASLR High entropy Randomization
    • Работа ASLR PEB/TEB Randomization
  • Ключи /GS и Enhanced /GS
  • Механизмы IE Protected Mode и Enhanced Protected Mode (EPM)
  • VTG (Virtual Table Guard)
  • Механизмы Heap hardening
    • Header encoding
    • Terminate on corruption
    • Guard pages
    • Allocation randomization
    • Safe unlinking
    • Header checksums
  • То, чего нет на картинке, но есть в Windows Server 2012 R2
    • Data Execution Prevention (DEP)
    • Export Address Table Access Filtering (EAT или EAF)
    • Heap Spray Allocation (HSA)
    • Null Page Allocation (NPA)
  • Механизмы ROP Mitigation
    • Механизм EMET LoadLib
    • Механизм EMET MemProt
    • Механизм EMET StackPivot
    • Механизм EMET SimExecFlow
    • Механизм EMET Caller Checks
    • Усиление механизмов ROP Mitigation

Приступим.

SEHOP

Разберём SEHOP подробнее, чем в статье про EMET 2.1, поскольку настройка и использование данной защитной технологии достаточно обширны.

Атака на Structured Exception Handler

В Windows есть такая штука – обработка исключений. Try-catch и всё такое. Исключения могут происходить как по независящим от приложения причинам (допустим, сбой в вызываемой функции), так и могут вызываться приложением осознанно. Обработка исключений идёт не одной функцией, а цепочкой – т.е. обработчик на уровне приложения, потом на уровне системы, например. Это нужно, чтобы приложение могло сделать свой обработчик исключительной ситуации, а система (или вначале подсистема, а потом ядро ОС) могло после сделать некие общие действия, характерные для данного исключения (освободить ресурсы, что-то очистить). Соответственно, есть схема атаки, кратко выглядящая так:

  1. Находим уязвимость, которая позволяет получить доступ к записи про цепочку обработчиков конкретного исключения. Обычно эта уязвимость – переполнение буфера в стеке конкретного thread’а. Структура одной записи в этой цепочке проста – указатель на функцию-обработчик и указатель на следующую запись.
  2. Можем как просто заменить один из адресов на адрес своей злонамеренной функции-обработчика, так и поставить заведомо некорректное значение адреса перехода – тогда с гарантией будет access violation exception, которое мы можем заранее переключить на наш обработчик и тоже получим управление.

Защита – SAFESEH и Structured Exception Handler Overwrite Protection (SEHOP)

Данная защита может быть реализована двумя способами – на уровне кода приложения и на уровне ОС. Конечно, хорошо, когда и там и там, но идеология EMET как раз во втором – чтобы защищать без переделывания приложения. Первый способ – SAFESEH.

Как работает и как задействовать SAFESEH

SAFESEH предполагает пересборку приложения с ключом /SafeSEH и доступен, начиная с Visual Studio 2003. При этой пересборке метаданные о цепочках обработки добавляются напрямую в исполняемый модуль, и система учитывает их при запуске приложения. Если система видит, что есть попытка передать управление в “непрописанную” точку кода, то срабатывает защита. Минусом SAFESEH, помимо обязательной перекомпиляции исполняемых модулей будет то, что система не сможет обработать ситуации, когда попытка передать управление идёт вне исполняемого файла.

Поэтому SafeSEH, конечно, хорошо, да и уже лет 10 как надо бы использовать при разработке ПО, но он не решает все вопросы.

Поговорим, как работает и как включить второй вариант – SEHOP.

Как работает и как включить SEHOP

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

SEHOP начинает свою работу с загрузки исполняемого модуля. Первым делом он добавляет в конец цепочки обработки исключений свою собственную запись – по сути, контрольную, и запишет всю цепочку обработчиков. После этого SEHOP ничего не делает, пока не будет вызвано исключение. Когда это случится, SEHOP пройдётся по цепочке и проверит – а можно ли, последовательно вызывая обработчики, дойти до контрольной записи? Если можно, то SEHOP скажет “ОК” и будет пошагово вызывать обработчики – не те, которые по факту, а те, которые он закэшировал. Поэтому SEHOP сможет и отследить факт атаки (сбойная цепочка), и игнорировать злонамеренные изменения.

Включаем SEHOP. Общие предпосылки – SEHOP включён на уровне ОС по-умолчанию, начиная с серверной Windows Server 2008, и существует, но выключен по-умолчанию в клиентских ОС, начиная с Vista. После установки EMET 4.0 SEHOP появится и на Windows XP / Windows Server 2003 (правда, это будет SEHOP только для явно указанных приложений, для самой ОС – нет). И да, SEHOP не будет работать в 64х битовых ОС для 64х битовых приложений, это пока не реализовано. Только 32-поверх-32 и 32-поверх-64.

Как включить SEHOP вручную на уровне ОС

Берём параметр DisableExceptionChainValidation типа DWORD32 и ставим его в нуль. Параметр можно найти здесь:

HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\kernel\DisableExceptionChainValidation

Если его нет, его надо создать. Работать начнёт после перезагрузки.

Как включить или выключить SEHOP вручную на уровне приложения

Зачем это нужно? Для того, чтобы не выключать SEHOP глобально из-за одного-двух несовместимых приложений. Плохой и ленивый админ руководствуется принципом “потыкал три минуты, какие-то глюки, забил на всё, пойду на форум напишу что венда г…”. Это лодырь, неосилятор и креативный класс, плохо быть таким. Правильный админ разберётся, что к чему, и оставит систему защищённой.

Берём параметр DisableExceptionChainValidation типа DWORD32 и тоже ставим его в нуль (если хотим включить) или в единицу (если хотим выключить). Параметр можно найти уже в другом месте:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\mstsc.exe

То, что выше – полное название ключа. Здесь mstsc.exe – название раздела, совпадающее с именем исполняемого модуля, для которого включается или выключается SEHOP, а параметр DisableExceptionChainValidation создаётся внутри этого раздела. Иногда, кстати, Microsoft называет этот параметр “IFEO” – это сокращение от Image File Execution Options.

Как включить или выключить SEHOP при помощи EMET

Откройте EMET (проще это сделать через иконку в system tray, правая кнопка и Open EMET) и глобальная настройка будет сразу видна: Настройка SEHOP в EMET 4.0 в Windows Server 2012 R2 Если нужна настройка для конкретного приложения – нажмите наверху Apps, выберите для упрощения просмотра вкладку Other (под Mitigations) и в списке найдите своё приложение. Настройка SEHOP для конкретного приложения в EMET 4.0 в Windows Server 2012 R2 Если приложения нет в списке, то его можно добавить. Если нужен конкретный экземпляр бинарника, лежащий в конкретном каталоге – добавьте через кнопку Add Application, она наверху. Рядом с ней Add Wildcard – это нужно, например, когда хочется применить настройки к данному бинарнику, где бы он не находился. Формат задания в этом случае – “*\mstsc.exe”. Если разбирать детально (это важно и я это сделаю один раз, в других методах mitigation’а будет аналогично), то после добавления EMET создаст ключ вида HKLM\SOFTWARE\Microsoft\EMET\mstsc.exe в котором явно пропишет все экземпляры данного приложения (полный путь к приложению будет названием ключа с типом REG_SZ), найденные на момент добавления wildcard’а. Сами по себе там приложения не появляются (можете себе представить в таком случае запуск EMET’а, когда в списке сотни приложений – он же не будет их искать по всему диску), поэтому надо запомнить, что после установки приложения, или обновления, или любого другого действия, которое может повлечь за собой появление новых экземпляров того же бинарника, нужно произвести операцию Add Wildcard повторно. Каждому из экземпляров EMET присвоит персональный GUID – он не будет совпадать с GUID данного приложения в CLSID, если таковой имеется, он генерится при добавлении. Берём этот GUID и идём в ключ: HKLM\SOFTWARE\Microsoft\EMET\_settings_\ Находим наш GUID и видим настройки конкретного приложения. SEHOP должен быть в единичке, если он включен, и в нуле, если выключен. Это – именно настройки EMET’а. Т.е. это он так свою конфигурацию хранит. В системе же то, что надо применять к конкретному приложению, будет храниться иначе: HKLM\SOFTWARE\Microsoft\Windwos NT\CurrentVersion\AppCompatFlags\Custom\ Подраздел будет называться опять же mstsc.exe, а в нём будут ссылки на два массива информации в формате SDB (древний достаточно формат, ещё с Windows 2000 тянется). Обычно они такие: {e1c810aa-f7cc-4aaf-ada1-181863075f9b}.sdb и {f8c4cc07-6dc4-418f-b72b-304fcdb64052}.sdb У данных ключей будут и значения – эти значения – timestamp’ы, ничего особенного нет. Что с делать с этими ключами и почему они одинаковые у всех приложений в данном разделе реестра? Это указатели на используемые при запуске приложений базы SDB-настроек. Сами эти базы Вы можете увидеть здесь: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\InstalledSDB Почему базы две? Тут мы подходим к интересной тонкости – дело в том, что у нас ведь не только есть сценарии “32х-битовые приложения поверх 32х битовой ОС” и “64х-битовые приложения поверх 64х битовой ОС”, но и достаточно часто встречающийся вариант “32х-битовые приложения поверх 64х битовой ОС”. В курсах Microsoft это мягко обходится и умалчивается, но на практике это часто бывает. Поэтому базы две – для native-приложений и для WoW64. И это надо учитывать в случае ручной настройки – ключ настроек приложения для сценария “32-поверх-64” будет другой: HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Custom\ Напомню, что в сценарии “64-поверх-64” SEHOP не работает. В общем, всё – с SEHOP разобрались. Пошли дальше.

ASLR

ASLR – это механизм, который “перемешивает” относительно случайным образом (насколько хорошо случайным – зависит от реализации в конкретной версии конкретной ОС – например, в NT 6.0, где технология появилась, случайность выражается числом 2^8) выделяемые программе страницы памяти (да и сами модули при загрузке), что затрудняет проведение целого класса атак, использующих предсказание расположения этих страниц относительно друг друга. Попробую пояснить на синтетическом примере. Допустим, есть некое приложение. Оно запрашивает 3 отдельных сегмента для данных – 1,2,3 – каждый по мегабайту. У этого приложения есть известная уязвимость, которая позволяет разместить выполняемый код в конце первого сегмента и начале второго. Поэтому станет возможным написание эксплойта, который будет точно знать, на сколько надо сдвинуть указатель выполнения, чтобы попасть в нужное место, потому что в случае без ASLR сегменты всегда будут фактически расположены в оперативной памяти как 1,2,3, и атака будет успешной, а в случае ASLR сегменты каждый раз будут менять расположение относительно друг друга (3,1,2 или 2,3,1 например) и атака станет возможна только в случае крайне редкого стечения обстоятельств. На самом деле, сейчас ASLR уже перемешивает так, чтобы сегменты никогда не располагались “стандартно”, поэтому атака станет невозможна вообще – вариант расстановки 1,2,3 не будет выбран никогда. По сути, ASLR является критичски важной технологией, особенно эффективной в связке с DEP (обе они по отдельности далеко не так идеальны, как кажется), поэтому её включение можно считать строго необходимым. Примечание: Ещё ASLR мешает целому классу атак на подмену адреса возврата (т.н. ret2libc), но это отдельная история. ASLR, подобно SEHOP, будет включаться как на уровне приложения, так и на уровне системы. А самое правильное – когда приложение собрано с учётом ASLR.

Как включить ASLR при сборке приложения в Visual Studio

Visual Studio, начиная с Visual Studio 2010, позволяет задать ключ /DYNAMICBASE, который явно укажет системе, что при загрузке данного модуля страницы в памяти надо перемешать. Как понятно, это может влиять на работу приложения, которое, например, разрабатывало с применением переходов по фиксированным адресам внутри модулей. Поэтому иногда при включении данного ключа потребуется менять код приложения – это не любят программисты, но это нужно. Поэтому разрабатывая ПО наличие ASLR надо учитывать на фазе проектирования.

Как включить ASLR при помощи EMET

Для начала разлочим значение “Always On”, которое для ASLR не всегда доступно из соображений стабильности работы системы. Идея в том, что может быть ситуация, когда принудительный ASLR для всех модулей системы убьёт какой-нибудь драйвер или сервис, помеченый как критический на фазе загрузки системы, и загрузиться не получится. По факту же, особенно в современных реалиях, где виртуализация серверных ОС – стандартная практика – данная ситуация уже не встречается, т.к. драйвера виртуального оборудования во-первых малочисленны, во-вторых уже на фазе сборки учитывают существование ASLR. Зайдём в ключ реестра, HKLM\SOFTWARE\Microsoft\EMET создадим там параметр EnableUnsafeSettings и выставим его в единицу. После перезапуска EMET откроем главное окно и выставим ASLR в Always On: Настройка ASLR Always On для всей системы в EMET 4.0 в Windows Server 2012 R2 Это – включение на уровне системы (будет работать для NT 6.0 и выше). Под “общесистемный” ASLR подпадут не только страницы данных, но и кода системных приложений. Теперь включим для отдельного приложения. Для этого зайдём в то же окно Apps и выберем там вкладку Memory: Настройка ASLR и BUR для конкретного приложения в EMET 4.0 в Windows Server 2012 R2 Целых два разных ASLR. Разберёмся.

Что такое MandatoryASLR для приложения

Это тот самый ASLR, расписаный выше. Перемешивать страницы он будет и для 32х битовых, и для 64х битовых приложений. Будет перемешиваться и куча, и стек, и PEB (Process Enviroment Block), и TIB’ы для отдельных thread’ов (TIB = Thread Information Block). Кстати, учтите, что в ситуации нехватки памяти в 32х битовых ОС до Windows 8 ASLR перестаёт работать, так как ему, выражаясь проще “особо размахнуться негде”. В NT 6.2 это поправили.

Что такое BottomUpASLR для приложения

Это то, что раньше называлось Bottom-Up Rand. Суть проста – к базовым адресам выделяемых сегментов (кучи, стека, и прочих) прибавляется случайное число байт (от 1 до 255), что, несмотря на казалось бы небольшой диапазон значений, делает ощутимо более сложной попытку доступа к “верхним” адресам внутри этих сегментов, используя сдвиг на фиксированное количество байт. Скажем проще – попытка будет неудачной и вызовет исключение. Если ASLR – это “перемешивание”, то BUR – это, наверное, “подрагивание”. :) Имеет смысл всегда включать обе этих технологии как взаимодополняющие. Теперь давайте вернёмся к стартовой картинке и попробуем разобраться, что чем называется из кучи видов ASLR, указанных там.

ASLR Stack Randomization

Это компонент стандартного MandatoryASLR для приложения.

ASLR Heap Randomization

Это компонент стандартного MandatoryASLR для приложения.

ASLR Image Randomization

Это факт того, что можно включать ASLR для приложения.

ASLR Force image Randomization

Это интереснее. Штука в том, что начиная с NT 6.2 изменилась логика загрузки dll для приложения, для которого включён MandatoryASLR. Если раньше надо было явно указать через тот же EMET “включи мне ASLR для этой dll’ки”, то теперь ASLR форсированно включается для всех dll, которые загружаются для приложения, для которого включен MandatoryASLR. Эти dll могут быть собраны без ключа /DYNAMICBASE – это ничего не изменит. ForcedASLR может быть явно включён и на уровне приложения – пример таких приложений – IE 10 и старше и Microsoft Office 2013.

ASLR Bottom-up Randomization

Это стандартный BottomUpASLR для приложения. В табличке правда почему-то пишется, что его нет в Windows XP SP3, хотя если туда поставить EMET 4.0, то можно включить BUR для отдельных приложений и будет работать.

ASLR Top-down Randomization

Это BottomUpASLR “вверх ногами” и только для ядра ОС. Суть в том же, что и у BottomUpASLR, только речь не только о прибавлении случайного числа байт, но и о вычитании.

ASLR High entropy Randomization

ASLR, в своей идее рандомизации, технически ограничен 32х битовой адресацией. High entropy Randomization – это то, что в 64х битовых ОС, начиная с Windows 8, для рандомизации используется не 8 бит, а 24, что делает практически неосуществимой специфичную атаку на brute force перебор адресов для перехода. Включать отдельно не надо – это само сработает, когда EMET 4.0 включит MandatoryASLR на Windows 8 x64 и выше. Работает, понятное дело, только для x64-приложений – поэтому когда пишут, что 64х битовый Microsoft Office и IE безопаснее 32х битовых вариантов – это правда.

ASLR PEB/TEB Randomization

Тут речь про то, что в ASLR перемешиваются не только сегменты данных/кода/стека, но и служебные структуры, про которые упомянуто выше. С ASLR вроде всё. Идём дальше.

/GS и Enhanced /GS

/GS – это защита от переполнения буфера. Суть её достаточно проста – компилятор добавляет в выделяемое место в стеке security cookie, который придумывается на ходу, после чего на выходе из целевой функции, которая запросила выделить память, проверяется – на месте ли cookie. Если значение поменялось – было переполнение, процесс аварийно завершается. Это опция компилятора, поэтому нужно, чтобы софт был собран с ней (и exe, и dll). Проблема в том, что /GS – достаточно простая проверка, и защищает не все функции – например, она не защищает массивы, где размер элемента больше двух байт (т.е. её заточили под строки char и wchar), и где размер массива меньше 5 байт. Простой пример – массивы указателей, или unsigned long’ов. Начиная с Visual Studio 2010, доступен вариант /GS:2, который и называется Enhanced GS, который сразу же является алиасом /GS (старый вариант работы /GS доступен при задании ключа компилятора /GS:1). Его преимущества просты – защита всех массивов данных плюс интеллектуальная проверка на фазе компиляции, надо ли защищать данный массив вообще (если не надо, то можно, например, выиграть в скорости). Пример – у Вас есть переменная, char[4], в которую в Вашем приложении может копироваться только две других – допустим, char[] = “Yes” и char[]=”No”. И вообще другие операции с ней в коде отсутствуют. Компилятор прикинет и подумает – зачем городить тут защиту, ставить cookie, генерить cookie, когда сам cookie больше и дольше ставить, чем копировать, а копирования в Вашу переменную чего-то большего, чем 4 байта, просто нет в коде. Можно сделать и ещё круче – включить strict_gs_check, и тогда будет проверяться вообще всё. Это параноидальный вариант, но, тем не менее, вполне разумный для приложений, предназначенных для работы в открытых сетях. Смотрим дальше.

IE Protected Mode и Enhanced Protected Mode (EPM)

Protected Mode появился в 7, а EPM – в 10й версии браузера. Что добавилось? Первое – это защита персональных данных пользователя путём проксирования всех обращений к файловой системе через “broker process”. Суть в том, что любая функция IE, которая запрашивает доступ к файлам, передаёт запрос этому процессу, а он уже взаимодействует с пользователем. Права плагину IE, который хочет файл, не выдаются – фактически, sandbox’инг. Второе – это защита 64х битовых процессов. Теперь она есть и работает – можете вспомнить, какой был геморрой во всех связках вида IE+плагины, когда если IE 64х битовый, а плагин 32х битовый, то из защитных мер вообще почти ничего не работало толком. Третье – более жесткие ограничения для отдельных вкладок, в которых открыты URL’ы, подпавшие под определение Internet. Эти вкладки, как отдельные процессы, не смогут получить доступ к доменным учётным данным пользователя, а также подключиться к ресурсам, подпадающим под классификацию Intranet. Это исключает ситуации вида “во вкладке что-то завелось, что от имени пользователя шарит по локальной сети”.

VTG (Virtual Table Guard)

Данная технология защиты предотвращает класс атак, описываемый словосочетанием “use after free”. Т.е. несанкционированного доступа к тому, что вроде как уже free. Так как основная цель подобных атак – веб-приложения, то неудивительно, что для код для предотвращения этих атак был добавлен в браузер IE 10 и последующие версии. Сама технология предотвращения работает так – на уровне runtime, когда класс C++ “включается” и заполняет таблицу методов, туда добавляются специальные случайные значения, а также перед каждым вызовом функции добавляется проверка этих значений. Если они срабатывают, то таблица не изменялась, если нет – то защищаемый класс и его методы скомпрометированы, приложение останавливается. Данную технологию можно использовать и для других приложений, но для этого опять же нужна их пересборка на Visual Studio 2012. А вообще надо указатели после free вручную занулять или пользоваться managed code.

Усиление защиты “кучи” – heap hardening

Под этим неласковым названием находится целый комплект технологий по улучшению защиты памяти. Что же в неё входит?

Header encoding

Оно же – часть Heap Entry Metadata Randomization. Каждый раз, когда приложение запрашивает новую “кучу”, создаётся заголовок и этот заголовок защищается, XOR’ясь со случайным числом, которое генерится и хранится в heap manager’е. И при каждом обращении заголовок “раскодируется”. Это, безусловно, увеличивает и целостность и сохранность информации.

Terminate on corruption

Встроенный менеджер памяти в NT 6.0 и старше будет выключать приложение в гораздо бОльшем перечне случаев, чем в Windows XP. Это будет включать в себя попытку двойного освобождения одного и того же блока памяти, попытку освобождения невыровненного по границе (обычно 8 байт) блока, а также всяких corruption of an uncommited range, heap header corruption (чексумма заголовка кучи не сошлась), или если по результату проверки цепочки больших виртуальных блоков, выделенных приложением (это от полумегабайта на 32х битовых и от мегабайта на 64х битовых прошли по цепочке и нашли, что кто-то из них выделен напрямую, то, что называется direct virtual allocation), buffer overrun / underrun, а также corruption of free block list, попыток write-after-free. Это всё отслеживает менеджер heap в usermode, поэтому действовать это будет только если приложение управляет памятью встроенными способами, а не аллоцирует себе здоровый кусок и само там что-то делает. Всё логично – хотите, чтобы работало надёжнее и улучшало безопасность без переписывания кода – используйте штатное API операционной системы.

Guard pages

Это обычные страницы, при создании которых указан модификатор PAGE_GUARD (в том же VirtualAllocEx или VirtualProtectEx). Суть в том, что когда будет предпринята попытка доступа к адресу внутри этой страницы, будет исключение STATUS_GUARD_PAGE_VIOLATION, которое можно будет обработать. Флаг PAGE_GUARD после этого будет снят. Этакая “растяжка” в оперативке. Благодаря Guard Pages приложения и ОС могут легко контролировать рост использования памяти или другие несанкционированые действия.

Allocation randomization

Алгоритм выделения блоков из кучи, начиная с Windows NT 6.0, стал выделять блоки памяти с рандомизацией – Вы это видели по описанию функционала ASLR. Кстати, начало heap у приложения теперь тоже выделяется рандомизированно – 5 бит рандомизации, но, по сути, добавляемых к остальным, плюс крайне усложняющие поиск служебных структур данных.

Технология Safe Unlinking

Появилась ещё в Windows XP SP2, по сути своей предотвращает атаку на heap в usermode (начиная с Windows 7 – аналогично и для pool-памяти ядра). Логика такова. При выделении блока памяти размером до 256 байт используется односвязанный список (так называемый lookaside list), он нам не интересен. Зато при выделении блоков от 256 до 4080 байт используется двусвязанный список, он и будет целью. В начале каждого выделенного блока будет 8ми байтовый заголовок, в котором будет информация о размере блока (если он большой – число выделенных страниц, а не байт), размер предыдущего блока и тип памяти (nonpaged / paged). Вот тут и начинается интересное, потому что при освобождении блока надо перезаписать указатели – чтобы цепочка выделенных блоков опять была цепочкой. Но если освободить сразу несколько блоков, притом грамотно подобрав значения, то возможна ситуация, когда арифметические операции над заголовком приведут к записи некорректного результирующего значения (в силу банального целочисленного переполнения, например). Это и предотвращает Safe Unlinking. Ключевое – начиная с Windows XP SP2 она просто есть, а начиная с Windows 7 она есть и работает для всех операций не только на heap, но и на pool.

Header checksums

Тут всё просто – в заголовках служебных структур появились чексуммы, которые проверяются (в том же Heap Header Cookie). Даже можно добавить ещё то, что называется Function Pointer Encoding – в структурах “кучи” указатели на функции опять же XOR’ятся со случайным значением, чтобы можно было защитить их от перезаписи. Табличку разобрали – но это ещё не всё. В Windows Server 2012 R2 есть ещё много интересного. Пробежимся.

То, чего нет на картинке, но есть в Windows Server 2012 R2

Data Execution Prevention (DEP)

DEP – одна из самых старых защитных мер, которая появилась ещё в Windows XP. Если очень обобщённо, то практически любое приложение, стартуя, резервирует для себя в оперативной памяти три типа страниц – программного кода, стека и т.н. “кучи” (heap). Количество их различается, но суть задач остаётся одинаковой – в страницах с программным кодом размещается сам код приложения, в стеке и куче – различные типы данных. DEP делает следующее – он помечает страницы с данными специальным флагом в одном из полей структуры PTE, чтобы в случае попытки передать туда указатель выполняемой инструкции было бы вызвано исключение STATUS_ACCESS_VIOLATION (0xC0000005) (которое можно перехватить, но Microsoft почему-то упорно называет его “необрабатываемым”). Т.е. функционал DEP адресно предназначен для ликвидации целого класса атак, которые проводятся следующим образом – нежелательный программный код копируется в область данных, а после на него каким-то образом передаётся управление. Если такое происходит – Вы видите окно с кодом 0xC0000005 и приложение закрывается. Кстати, из-за этого DEP мешает целому классу “кряков” и подобных приложений. Замечу заодно, что самих структур PTE в ОС будет не бесконечное, а ограниченное число. И этот максимум будет иметь зависимость, например, от использования ключа /3GB, который многие безапелляционно предлагают “всегда ставить в 32х битовых ОС”. Если Вы получаете Stop 0x0000003F NO_MORE_SYSTEM_PTES или Stop 0x000000D8 DRIVER_USED_EXCESSIVE_PTES – причиной вполне может быть установка данного ключа. Поэтому лучше переходите на 64х битовую ОС. Microsoft различает два вида DEP – аппаратный и программный. На самом деле программный DEP – это не DEP, а доп.проверка, которая перекликается с функционалом SEHOP, который мы рассмотрели выше. Вкратце, “программный DEP” представляет из себя проверку перед вызовом обработчика исключения – расположен ли этот обработчик в памяти, помеченой как “не содержащая исполняемого кода” или нет. Если расположен, происходит такое же исключение STATUS_ACCESS_VIOLATION. Применяется только к программам, собранным без ключа /SafeSEH. Работать этот “программный DEP” будет только для программного кода, выполняющегося в userspace – для кода, выполняющегося в режиме ядра ОС, никакого “программного DEP” вообще нет. То есть если у Вас процессор без поддержки DEP, то включение “программного DEP” – это частичная защита и только приложений, а не самой ОС. Такой процессор Вы сейчас и не встретите особо, так что просто забудьте, что такое было – функция No-execute Page-protection (NX) у AMD или бит Execute Disable (XD) у Intel есть сейчас во всех процессорах уже лет 10 как. Теперь как включить эту базовую меру безопасности.

Включаем DEP на уровне системы

Сразу ключевой момент – в 64х битных ОС DEP работает вообще всегда для всего 64х битового кода, а видимые Вам “настройки DEP” влияют лишь на 32х битовый код, выполняемый через WoW64. Выключить DEP на таких системах для native x64 code нельзя. Включение DEP через EMET выглядит так: Включение DEP на уровне системы в EMET 4.0 в Windows Server 2012 R2 Всегда глобально включайте DEP в Always On – это старая и фундаментальная защитная технология, при отсутствии которой многие другие (ASLR) ощутимо теряют в эффективности. Пойдём дальше.

Что такое Export Address Table Access Filtering (EAT или EAF)

Конкретной информации по реализации EAF (Export address table Access Filtering) в Windows достаточно мало. Задачей этой технологии является адресная борьба с шеллкодами, и реализуется это (судя по документации) через фильтрацию чтения EAT у модулей kernel32.dll и ntdll.dll (используя аппаратные breakpoints), блокирование доступа инструкции в случае, если IP (который Instruction Pointer, а не то, что обычно) указывает на адрес вне текущего модуля (проверяется через Vectored Exception Handler). В принципе, такое должно блокировать большинство шеллкодов. Т.е. работает EAF, говоря проще, следующим образом – ставит аппаратный breakpoint на доступ к EAT у указанных модулей, и когда breakpoint срабатывает, EAF проверяет – является ли код, который пытается обратиться к EAT, “правильным” или добавлен в модуль каким-то эксплойтом. EAF работает и для 64х битных процессов, и для 32х битных. Кстати, если совсем запутались, то EAT – это таблица, а EAF – отслеживание тех, кто её читает Вы можете включить EAF для явно указанных приложений – EMET создаст для них специальные записи в реестре (они будут содержать информацию о том, что при запуске этих приложений необходимо использовать EAF). Запускать EMET каждый раз при старте системы не нужно – он лишь включает EAF для указанных приложений, а реализует логику EAF операционная система.

Что такое Heap Spray Allocation (HSA)

Heap Spray Allocation (HSA), пожалуй, одна из самых “древних” атак из рассматриваемых. Логика атаки достаточно проста – заполнить максимально доступное количество памяти процесса-жертвы мелкими блоками, в которых будет, допустим, переход на исполняемый код эксплойта. Вариаций очень много – это может быть и заполненный единственным переходом файл swf-формата (который точно будет помечен DEP как исполняемый), может и что-то другое. Важно – что это будет много одинаковых блоков, а на кого удастся перенаправить выполнение – не важно, каждый приведёт к нужному результату, переходу на злонамеренный код. EMET позволяет обнаружить начало такой атаки и предотвратить её. Включается только для выбранного приложения.

Что такое Null Page Allocation (NPA)

Это защита от достаточно интересной атаки, базирующаяся на предположении, что зловредный код “займёт” для себя страницу с адресом 0x0 в адресном пространстве приложения. Для этого сама программа – EMET – занимает адрес 0x0. Впрок, так сказать. Что интересно, если вызвать VirtualAlloc с параметром 0, то VirtualAlloc (что, в общем-то, логично) выделит память по адресу, который выберет сама, а не по нулевому. Для того, чтобы “застолбить” за собой такой адрес, как предполагается, применяется вызов NtAllocateVirtualMemory, у которой запрашивается адрес 0x1, при попытке выделения которого выделяется блок, начинающийся с 0x0. На данный момент зловредов, использующих эту возможность, не обнаружено. Включить NPA можно как и EAF – только для явно указанных приложений, а не на уровне системы. Когда эта технология включена, “нулевая” страница при запуске приложения будет занята в профилактических целях. Теперь про механизмы ROP Mitigations (доступны для отдельных приложений в одноименной вкладке в разделе Application Configuration): Механизмы ROP Mitigation в EMET 4.0 для Windows Server 2012 R2

Механизмы ROP Mitigation

Механизм EMET LoadLib

Механизм достаточно прост. Суть его в том, что EMET будет отслеживать все запросы на подгрузку библиотек, и если результатом будет попытка загрузить библиотеку с UNC-расположения (например, вида \\178.159.49.227\c$\crypt32.dll), то попытка будет пресечена. Этот механизм имеет смысл включать, когда Вы уверены, что подпадающий под неё exe-модуль никогда не будет подгружать библиотеки не с локального хоста. Практически всегда так и есть, поэтому вполне логично включить этот механизм. Это предотвратит развитие потенциально удачной атаки.

Механизм EMET MemProt

Простая штука – сегменты стека блокируются для выполнения кода. Развитие DEP, так сказать – только DEP блокировал сегменты данных, а MemProt – стека. Включение обоих приведёт к тому, что адрес следующей выполняемой инструкции сможет быть только внутри сегментов кода и никаких других. Надо включать.

Механизм EMET StackPivot

EMET будет отслеживать, не перенаправляются ли обращения к сегментам, помеченым как стек. Т.е. если в ходе работы ПО будет обращение к стеку, но оно будет использовать новый адрес в памяти – EMET, отслеживая историю обращений, поймёт, что что-то пошло не так, предположит, что имеет место атака, и остановит работу приложения. Целесообразно включать на всём ПО, т.к. штатных ситуаций, когда ПО делает push в нормальный сегмент стека, а данные для pop почему-то забираются из другого, практически нет.

Механизм EMET SimExecFlow

EMET будет пробно анализировать некоторое количество инструкций, следующих за возвратом из критичной функции (стандартно это 1, но можно и увеличить, открыв в EMET-настройках конкретного приложения в реестре): Устанавливаем глубину анализа кода EMET 4.0 В случае, если поведение распознаётся как некорректное, приложение будет остановлено. Я устанавливаю 50.

Механизм EMET Caller Check

Один из самых эффективных механизмов. EMET будет отслеживать ситуацию, когда в критичную функцию вернулось управление, но почему-то не путём выполнения инструкции RET, а иным способом. Это отсекает целый класс хитрых механизмов, базирующихся на логике “не вызывать критичную функцию напрямую, т.к. это легко отследить, а имитировать, что мы возвращаемся в неё после вызова другой”. Как самый эффективный механизм, данный является и самым проблемным с точки зрения совместимости. Проверьте тщательно функционирование всего ПО, для которого примените этот механизм.

Усиление механизмов ROP Mitigation

В версии EMET 4.0 появились дополнительные методы, которые заблокировали найденные с момента выхода версии EMET 3.5 Preview методы защиты. Их три и они находятся во вкладке Application Configuration.

Блокировка низкоуровневых функций kernelbase!VirtualAlloc и ntdll!NtAllocateVirtualMemory

Ранее EMET делал хук только для kernel32!VirtualAlloc, теперь, включив пункт настроек под названием Deep Hooks, Вы включите отслеживание EMET’ом использования данных API.

Anti Detours – блокировка перехода к нехорошему коду после имитации начала “нормальной” функции

Один из, на мой взгляд, красивых способов обхода – известно, насколько глубоко EMET “пасёт” вызываемый код, поэтому можно скопировать кусок от начала “хорошего варианта функции”, а дальше передать управление на нужный код. Теперь, включив опцию Anti Detours, Вы отсечёте такую возможность.

Отключение заблокированных API-вызовов

Атака такого вида была продемонстрирована на CanSecWest 2013 – вкратце, там вызывалась старая API-функция ntdll!LdrHotPatchRoutine, игнорировавшая DEP и ASLR, и через неё шла атака. Включив в настройках опцию “Banned Functions”, Вы отсечёте и эту возможность. Это, грубо говоря blacklist старых API-функций, который сейчас состоит из этой одной функции – но, возможно, далее это изменится. :)

Что ж, как видите, количество встроенного в ОС функционала – вполне даже приличное. И в нём надо разбираться, чтобы эффективно применять. Чтобы не быть “линуксикспертами по безопасности”, у которых безопасность – это годами порты открывать-закрывать на файрволе и рута запаролить, а остальное “в линухе само по себе идеально”. Всё гораздо интереснее и увлекательнее, чем веровать в “априори неуязвимые системы”. Их не было, нет и не планируется. Поэтому нужно много знать и много работать. Безопасность – отличная сфера IT-науки в плане совершенствования ума и математического подхода к проблематике.

Надеюсь, что для вас вопросы безопасности ОС теперь стали чуть прозрачнее. Удачного применения!

Возможно, вам будет также интересно почитать другие статьи про EMET на нашей Knowledge Base

Ruslan V. Karmanov

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