Безопасность UEFI. Оценка защищенности UEFI с помощью CHIPSEC

Безопасность UEFI

Здравствуйте, друзья! В сегодняшней статье мы рассмотрим схему функционирования и устройство прошивки UEFI на материнских платах с процессорами и чипсетами Intel, протестируем ее с помощью CHIPSEC Framework и сделаем ряд не очень утешительных выводов касательно безопасности UEFI.

Unified Extensible Firmware Interface

После подачи питания на аппаратную платформу ЭВМ должна произойти корректная инициализация оборудования и выбор загрузчика операционной системы. Если раньше эту функцию выполнял всем известный BIOS Legacy, то со временем производители аппаратных платформ пришли к использованию более усовершенствованной технологии — UEFI.

Некоторые отличия между BIOS Legacy и UEFI отражены в сравнительной таблице.

BIOS Legacy UEFI
Поддерживаемые режимы работы процессора Режим реальных адресов Режим реальных адресов, защищенный режим работы процессора
Поддержка виртуальной памяти Не поддерживает Поддерживает
Объем используемой оперативной памяти 1 Мбайт Не ограничен
Пространство опционального ПЗУ (Option ROM) 1 Мбайт Не ограничено
Доступ к регистрам 16-битный 16-битный, 32-битный, 64-битный
Независимость от архитектуры Не обеспечивает Обеспечивает
Язык программирования Ассемблер Си/ассемблер
Функция безопасной загрузки Отсутствует Присутствует
Таблица разделов жесткого диска MBR GPT

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

Изменениями в спецификации управляет сообщество Unified Extensible Firmware Interface Forum, основная задача которого — расширять и улучшать существующую спецификацию, добавляя новые функциональные возможности и исправляя текущие недостатки. Для разработчиков программных компонентов спецификация UEFI предоставляет возможности повторного использования кода, расширяемости, модульности, а также легкого прототипирования в процессе разработки.

Хорошо это или плохо? С одной стороны, расширяемость и модульность позволяют разработчикам наделять прошивку дополнительными функциональными возможностями. С другой — обилие программного кода делает ее более уязвимой. Так как низкоуровневое программное обеспечение прошивки UEFI первостепенно в системе, уровень защищенности прошивки играет основную роль при оценке защищенности всей ЭВМ.

Аппаратное расположение прошивки UEFI

Совокупность всех прошивок в системе называют прошивкой платформы. Как правило, она расположена во флеш-памяти SPI (Flash memory). В этой же памяти располагается прошивка UEFI.

Аппаратное расположение прошивки платформы
Аппаратное расположение прошивки платформы

Для того чтобы система могла различать прошивки между собой, флеш-память делится на регионы. Доступ к регионам разграничивает встроенный в чипсет PCH SPI-контроллер (в современных системах PCH играет роль южного моста). На скриншоте представлен дамп флеш-памяти SPI в утилите UEFITool.

Дамп флеш-памяти SPI в UEFITool
Дамп флеш-памяти SPI в UEFITool

Описание некоторых регионов флеш-памяти SPI:

  • Flash Descriptor (Descriptor region) — регион дескриптора, содержащий основные смещения и настройки флеш-памяти SPI;
  • GbE region — регион, содержащий основные настройки сетевой карты;
  • ME region — регион, содержащий прошивку ME (ME выполняет функции управления энергопотреблением, функции инициализации и запуска основного процессора);
  • UEFI region (BIOS region) — содержит прошивку UEFI;
  • PDR region — регион, предназначенный для описания возможностей, зависящих от платформы.

Образы и протоколы в UEFI

Спецификация UEFI позволяет расширять прошивку через загрузку образов. Образ в UEFI может быть представлен в виде отдельного драйвера или приложения (наглядный пример — приложение UEFI Shell). Структура любого образа описывается форматом PE32/PE32+.

Расширение, а также идентификация компонентов UEFI выполняется с помощью GUID-записей. GUID представляет собой уникальный 128-битный идентификатор, соответствующий тому или иному компоненту прошивки.

Некоторые образы UEFI в UEFITool
Некоторые образы UEFI в UEFITool

Любое устройство или образ в UEFI имеют собственный протокол обработки. Каждый протокол состоит из GUID и структуры интерфейса протокола. Структура интерфейса протокола содержит функции и данные, которые используются для доступа к тому или иному устройству. Управление протоколами обеспечивают специальные службы UEFI (LocateProtocol, OpenProtocol и другие).

Основные фазы функционирования ПО UEFI

Работу ПО UEFI условно можно разбить на два этапа:

  • во время инициализации платформы;
  • во время загрузки и работы ОС.

Схема функционирования прошивки UEFI во время инициализации платформы
Схема функционирования прошивки UEFI во время инициализации платформы

Ниже описано, за что отвечает каждая фаза.

SEC:

  • обработка всех событий перезапуска платформы;
  • создание хранилища временной памяти;
  • проверка целостности и подлинности элементов прошивки;
  • подготовка и передача необходимой информации в следующую фазу.

PEI:

  • инициализация постоянной памяти;
  • описание памяти в специальных структурах Hand-Off Blocks (HOBs);
  • описание адресов размещений микропрограмм в HOBs-структурах;
  • передача управления в фазу среды выполнения драйверов.

DXE:

  • инициализация служб загрузки, служб реального времени выполнения и служб DXE (DXE Services);
  • обнаружение и выполнение драйверов DXE;
  • инициализация процессора, набора микросхем и компонентов платформы.

BDS:

  • инициализация консольных устройств;
  • загрузка драйверов устройств;
  • попытка загрузки в ОС;
  • если попытка не удалась, повторно выполняется фаза DXE.

В качестве отдельной фазы выделяют режим системного управления (SMM).

Режим системного управления (SMM)

SMM — специальный режим работы, в который процессор переходит через вызов прерывания управления системой (SMI). Среда выполнения кода SMM инициализируется драйверами служб загрузки и находится в специально выделенной привилегированной области памяти SMRAM (System Management Random Access Memory).

Разработчики аппаратных платформ могут использовать данный режим для любых целей (управление питанием, обработка системных ошибок, обеспечение безопасности прошивки и другие).

Режим системного управления считается режимом –2 кольца защиты процессора, а в связи с тем, что SMI-прерывание легко вызвать из ядра ОС, он представляет особый интерес для злоумышленника.

SMRAM

SMRAM — это защищенная на уровне PCH область физической памяти, которая представляет собой адресное пространство при входе в SMM-режим. Эта область памяти содержит код и данные обработчиков SMI-прерываний, а также сохраненный контекст процессора и операционной системы перед вызовом SMI-прерывания.

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

Параметры управления доступом к SMRAM прописаны в конфигурации 8-битного регистра SMRAM Control.

SMI-прерывания

SMI (System Management Interrupt) — единственный способ перевести процессор в режим системного управления. SMI представляет собой внешнее прерывание, работающее независимо от механизма обработки прерываний и исключений процессора.

SMI-прерывания бывают аппаратными, системными и программными. Со списком всевозможных событий, генерирующих SMI-прерывания, можно ознакомиться здесь (Power Management).

Вызвать программное SMI-прерывание можно при помощи записи в порт ввода-вывода APM (Advanced Power Management). Данный порт имеет два регистра: APM_CNT (0xB2) и APM_STS (0xB3).

APM_CNT (0xB2) — управляющий регистр. Для вызова SMI-прерывания необходимо записать в этот регистр байт — номер (код) прерывания.

Запись в регистр APM_CNT с помощью утилиты Read & Write
Запись в регистр APM_CNT с помощью утилиты Read & Write

APM_STS (0xB3) — регистр статуса. Запись в данный регистр не вызывает SMI-прерывание, тем не менее, он может быть использован для передачи дополнительной информации обработчику SMI-прерывания. SMI-прерывание будет сгенерировано только в том случае, если в конфигурационном регистре APM установлен бит APMC_EN.

Вызов SMI-прерывания в дизассемблированном коде прошивки
Вызов SMI-прерывания в дизассемблированном коде прошивки

Обработчики SMI-прерываний

Обработчики SMI-прерываний вызываются процессором при возникновении соответствующего SMI-прерывания и возвращаются в операционную систему с помощью специальной инструкции RSM. Основным механизмом передачи информации и регулирования деятельности обработчиков SMI-прерываний в режиме SMM является SMST (System Management System Table). SMST обеспечивает доступ к службам режима SMM.

CHIPSEC

Что такое CHIPSEC?

CHIPSEC представляет собой фреймворк, написанный на Python. Его можно использовать как из командной строки, так и в качестве импортируемых Python-модулей, что позволяет с легкостью писать собственные тесты для оценки защищенности. Первая версия фреймворка была представлена в 2014 году на конференции CanSecWest.

CHIPSEC можно использовать из операционной системы Windows, Linux, macOS или вообще без операционной системы. В таком случае понадобится UEFI Shell — стандартное UEFI-приложение.

[box type=»info» align=»» class=»» width=»»]Последние наборы системной логики (Intel 300 Series) и процессоры Core 8-го поколения (Coffee Lake) не поддерживаются CHIPSEC.[/box]

Установка

Разберем установку фреймворка в ОС Linux и Windows. Будем следовать инструкциям из мануала. Там же можно найти инструкции по установке CHIPSEC в macOS и по запуску в UEFI Shell.

[box type=»warning» align=»» class=»» width=»»]Настоятельно рекомендуется устанавливать и использовать фреймворк только на тестовых ЭВМ.[/box]

Linux

1. Устанавливаем зависимости.

Для систем с пакетным менеджером yum:

Для систем с пакетным менеджером apt:

2. Устанавливаем CHIPSEC.

Проще всего установить из PyPI:

Кроме того, установить можно вручную:

3. Отключаем безопасную загрузку для нормальной работы драйвера.

Windows

Для установки CHIPSEC в Windows необходимо вручную собрать и подписать (только на Windows x64) драйвер для взаимодействия фреймворка с компонентами аппаратной платформы.

  1. Устанавливаем необходимые пакеты.
  2. Собираем и подписываем драйвер по отдельной инструкции.
  3. Копируем подписанный драйвер в директорию <CHIPSEC_DIRECTORY>\chipsec\helper\win\win7_amd64 или <CHIPSEC_DIRECTORY>\chipsec\helper\win\win7_ x86 в зависимости от архитектуры процессора на тестируемой системе.
  4. Только после того, как драйвер окажется в нужной директории, устанавливаем CHIPSEC.

В данном случае подписанный драйвер следовало положить сюда: \Lib\site-packages\chipsec\helper\win\win7_amd64\chipsec_hlpr.sys.
При корректной установке в директории \Scripts должны появиться исполняемые файлы с двумя основными модулями CHIPSEC.
Основные модули CHIPSEC

  1. Отключаем обязательную проверку подписи драйверов. Это необходимо делать после каждого перезапуска системы.
  • Переходим в меню дополнительных параметров загрузки:
  • «Поиск и устранение неисправностей → Дополнительные параметры → Параметры загрузки → Перезагрузить».
  • В появившемся после перезагрузки списке команд выбираем «Отключить обязательную проверку подписи драйверов».

Данный способ (пункт 5) работает без отключения опции безопасной загрузки. В качестве альтернативы можно отключить безопасную загрузку и выполнить следующие команды в CMD (Administrator):

После чего устанавливаем тестовый режим работы системы и перезагружаемся.

Для того чтобы вернуть систему в первоначальное состояние, выполняем обратные команды и перезагружаемся:

Описание модулей CHIPSEC

Две основные утилиты в CHIPSEC — chipsec_main и chipsec_util. Утилита chipsec_util содержит набор инструментов для взаимодействия с аппаратной платформой. Чтобы просмотреть весь набор функций, предоставляемый данной утилитой, достаточно выполнить команду chipsec_util в командной строке (результат).

Утилита chipsec_main запускает тесты. Чтобы запустить стандартный набор тестов для оценки защищенности аппаратной платформы, выполняем chipsec_main в командной строке (полный лог).

Результат работы chipsec_main
Результат работы chipsec_main

Для запуска отдельного модуля с тестом можно воспользоваться опцией -m или —module.

Запуск модуля common.bios_kbrd_buffer
Запуск модуля common.bios_kbrd_buffer

Полный список опций и формат возвращаемого значения chipsec_main можно посмотреть здесь. Список поддерживаемых CHIPSEC аппаратных платформ — здесь. Если платформа не поддерживается, пользоваться фреймворком все равно можно. В таком случае CHIPSEC пропустит все тесты, специфичные для конкретных аппаратных платформ.

Дополнительные опции chipsec_main
Дополнительные опции chipsec_main

Каждый из отдельных тестов CHIPSEC создан на основании реальных атак или рекомендаций по безопасной разработке прошивки. В таблице описаны основные тесты защищенности UEFI. За более подробной информацией можно обратиться к мануалу CHIPSEC.

Общая оценка защищенности

Название модуля Описание модуля
common.secureboot.variables Проверяет переменные безопасной загрузки UEFI (Secure Boot key/whitelist/blacklist), производит собственные попытки модификации переменных (переменные должны иметь правильные атрибуты доступа и защиту от несанкционированной модификации)
common.uefi.access_uefispec Проверяет атрибуты доступа глобальных переменных UEFI на соответствие спецификации
tools.uefi.blacklist Проверяет компоненты прошивки UEFI (прошивка не должна содержать вредоносных компонентов, определенных в специальном конфигурационном файле)
tools.uefi.whitelist Генерирует устойчивый список образов UEFI, после чего сверяет новые состояния образов с данным списком во избежание модификаций
common.bios_kbrd_buffer Проверяет буфер клавиатуры BIOS на наличие паролей BIOS/HDD/pre-bot, чтобы предотвратить атаку, описанную здесь (в идеале буфер клавиатуры BIOS должен быть пустым)
common.uefi.s3bootscript Проверяет безопасность сценария загрузки из режима сна S3, реализованного на базе прошивок UEFI. Основанием для создания данного модуля послужила уязвимость CVE-2014-8274. Примеры атак: 1, 2, 3
common.ia32cfg Проверяет архитектурные особенности IA32/IA64 (архитектурные особенности, включая регистры MSR, должны быть правильно сконфигурированы и заблокированы)
tools.smm.rogue_mmio_bar Пытается создать поддельные диапазоны MMIO (Memory-mapped I/O) в памяти, переместить аппаратное обеспечение MMIO BAR (MMIO Basic) в поддельную область памяти, после чего наблюдает за изменениями, сделанными обработчиками SMI-прерываний в перемещенном диапазоне MMIO

Оценка защищенности флеш-памяти SPI

Название модуля Описание модуля
common.bios_wp Проверяет возможность модификации флеш-памяти SPI. Тест основан на проверке регистров чипсета PR0-PRN и флагов регистра BIOS_CNTL
common.bios_smi Проверяет конфигурацию событий SMI. Если конфигурация событий SMI настроена неправильно, теряет смысл защита от перезаписи, основанная на флагах регистра BIOS_CNTL
common.spi_desc Считывает SPI Flash Descriptor, проверяет программную возможность его модификации
common.spi_fdopss Проверяет значение бита FDOPSS регистра HSFS контроллера SPI, сигнализирующего о перезаписи SPI Flash Descriptor
common.spi_lock Проверяет значение бита FLOCKDN регистра HSFS контроллера SPI. Если FLOCKDN не установлен, конфигурация SPI-контроллера, включая PR-регистры, может быть модифицирована злоумышленником
common.bios_ts Проверяет блокировку региона с UEFI во флеш-памяти SPI

Оценка защищенности SMM

Название модуля Описание модуля
common.smm Проверяет конфигурацию регистра SMRAM Control во избежание доступа к SMRAM
remap Проверяет возможность переназначения SMRAM
common.smrr Проверяет возможность реализации атаки SMM cache poisoning
tools.smm.smm_ptr Проверяет возможность реализации атаки типа проверки указателей
smm_dma Проверяет возможность реализации DMA-атаки

CHIPSEC в Python

Утилиты chipsec_main и chipsec_util можно использовать не только из командной строки, но и в качестве импортируемых Python-модулей. Это позволяет создавать собственные сценарии для оценки защищенности аппаратной платформы или просто использовать функциональность chipsec_util в Python.

Чтобы выполнить необходимую команду, передаем массив с опциями в функцию chipsec_main.main() или chipsec_util.main(). Например, так можно вызвать программное SMI-прерывание с кодом 0x0E:

Вызов программного SMI-прерывания в Python с помощью chipsec_util
Вызов программного SMI-прерывания в Python с помощью chipsec_util

В качестве примера использования CHIPSEC в Python был написан скрипт chipsec_script.py. Он запускает определенный набор модулей CHIPSEC и делает вывод о состоянии защищенности аппаратной платформы.

Результат работы скрипта chipsec_script.py
Результат работы скрипта chipsec_script.py

Практические результаты

Мы протестировали данным скриптом четыре аппаратные платформы. Результаты получились следующие (логи):

Аппаратная платформа FAIL (защита не обеспечена) WARNING (необходимы дополнительные проверки)
Mobile 2rd Generation Core Processor (Sandy Bridge CPU / Cougar Point PCH) common.bios_wp, common.bios_smi common.bios_kbrd_buffer
Mobile 3rd Generation Core Processor (Ivy Bridge CPU / Panther Point PCH) common.bios_wp, common.bios_smi common.bios_kbrd_buffer
Mobile 7th Generation Core Processor (Kabylake U) common.spi_desc common.uefi.s3bootscript
Unknown Platform smm_dma

Видим, что платформы c архитектурами Intel Mobile 2rd Generation и Mobile 3rd Generation уязвимы перед модификацией флеш-памяти SPI:

  • проигнорирована защита, основанная на использовании регистров PR0-PRN;
  • не выставлены флаги регистра BIOS_CNTL;
  • неправильно настроена конфигурация событий SMI, что позволяет подавить вызов SMI-прерывания при попытке модификации флеш-памяти SPI.

У платформы c архитектурой Intel Mobile 7th Generation отсутствует защита от программной модификации SPI Flash Descriptor.

Заключение

UEFI — это root of trust всей электронно-вычислительной системы, и безопасность прошивки UEFI заслуживает отдельного внимания.

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

CHIPSEC Framework позволяет понять, насколько прошивка UEFI соответствует рекомендациям по безопасной разработке, а также оценить ее устойчивость перед известными атаками.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий