Хакер - Пентест UEFI. Оцениваем защищенность прошивки UEFI с помощью CHIPSEC
Содержание статьи
- Unified Extensible Firmware Interface
- Аппаратное расположение прошивки UEFI
- Образы и протоколы в UEFI
- Основные фазы функционирования ПО UEFI
- Режим системного управления (SMM)
- SMRAM
- SMI-прерывания
- Обработчики SMI-прерываний
- CHIPSEC
- Что такое CHIPSEC?
- Установка
- Описание модулей CHIPSEC
- CHIPSEC в Python
- Практические результаты
- Заключение
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?
- Нет, поскольку прошивки разных устройств имеют массу отличий
- Да, поскольку UEFI использует стандартный интерфейс и содержит типовые компоненты
- Теоретически — да, но дальше отдельных PoC дело пока не движется
Аппаратное расположение прошивки UEFI
Совокупность всех прошивок в системе называют прошивкой платформы. Как правило, она расположена во флеш-памяти SPI (Flash memory). В этой же памяти располагается прошивка UEFI.
Аппаратное расположение прошивки платформы
Для того чтобы система могла различать прошивки между собой, флеш-память делится на регионы. Доступ к регионам разграничивает встроенный в чипсет PCH SPI-контроллер (в современных системах PCH играет роль южного моста). На скриншоте представлен дамп флеш-памяти 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 имеют собственный протокол обработки. Каждый протокол состоит из GUID и структуры интерфейса протокола. Структура интерфейса протокола содержит функции и данные, которые используются для доступа к тому или иному устройству. Управление протоколами обеспечивают специальные службы UEFI (LocateProtocol, OpenProtocol и другие).
Основные фазы функционирования ПО 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-прерывание легко вызвать из ядра ОС, он представляет особый интерес для злоумышленника.
Может ли вредоносный код быть записан в UEFI?
- Нет. В UEFI есть проверка контрольных сумм, контроль записи и другие низкоуровневые механизмы защиты
- Внедрить троян в UEFI из ОС не выйдет, но он может быть «предустановлен»
- Да, и это уже давно делают
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_STS (0xB3) — регистр статуса. Запись в данный регистр не вызывает SMI-прерывание, тем не менее он может быть использован для передачи дополнительной информации обработчику SMI-прерывания. SMI-прерывание будет сгенерировано только в том случае, если в конфигурационном регистре APM установлен бит APMC_EN.
Вызов 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-приложение.

INFO
Последние наборы системной логики (Intel 300 Series) и процессоры Core 8-го поколения (Coffee Lake) не поддерживаются CHIPSEC.
Установка
Разберем установку фреймворка в ОС Linux и Windows. Будем следовать инструкциям из мануала. Там же можно найти инструкции по установке CHIPSEC в macOS и по запуску в UEFI Shell.

WARNING
Настоятельно рекомендуется устанавливать и использовать фреймворк только на тестовых ЭВМ.
Linux
Сначала устанавливаем зависимости. Для систем с пакетным менеджером yum:
> yum install kernel kernel-devel-$(uname -r) python python-devel gcc nasm redhat-rpm -config
> pip install setuptools
Для систем с пакетным менеджером apt:
> apt-get install build-essential python-dev python gcc \ linux-headers-$(uname -r) nasm
> pip install setuptools
Затем устанавливаем CHIPSEC. Проще всего установить из PyPI:
> pip install chipsec
Кроме того, установить можно вручную:
> git clone https://github.com/chipsec/chipsec
> python setup.py install
Наконец, отключаем безопасную загрузку для нормальной работы драйвера.
Windows
Для установки CHIPSEC в Windows необходимо вручную собрать и подписать (только на Windows x64) драйвер для взаимодействия фреймворка с компонентами аппаратной платформы.
Сначала устанавливаем необходимые пакеты.
> pip install setuptools
> pip install pywin32
Затем собираем и подписываем драйвер по отдельной инструкции. Копируем подписанный драйвер в директорию <CHIPSEC_DIRECTORY>\chipsec\helper\win\win7_amd64 или <CHIPSEC_DIRECTORY>\chipsec\helper\win\win7_ x86 в зависимости от архитектуры процессора на тестируемой системе.
После того, как драйвер окажется в нужной директории, устанавливаем CHIPSEC.
> pip install chipsec
В данном случае подписанный драйвер следовало положить в файл <PYTHON_DIRECTORY>\Lib\site-packages\chipsec\helper\win\win7_amd64\chipsec_hlpr.sys. При корректной установке в директории <PYTHON_DIRECTORY>\Scripts должны появиться исполняемые файлы с двумя основными модулями CHIPSEC.
Основные модули CHIPSEC
Отключаем обязательную проверку подписи драйверов. Это необходимо делать после каждого перезапуска системы:
-
Переходим в меню дополнительных параметров загрузки:
> shutdown /r /t 0 /o -
«Поиск и устранение неисправностей → Дополнительные параметры → Параметры загрузки → Перезагрузить».
- В появившемся после перезагрузки списке команд выбираем «Отключить обязательную проверку подписи драйверов».
Данный способ работает без отключения опции безопасной загрузки. В качестве альтернативы можно отключить безопасную загрузку и выполнить следующие команды в CMD (Administrator):
> BcdEdit /set noIntegrityChecks ON
> BcdEdit /set loadoptions DISABLE_INTEGRITY_CHECKS
После чего устанавливаем тестовый режим работы системы и перезагружаемся.
> BcdEdit /set TESTSIGNING ON
> shutdown -r -t 0
Чтобы вернуть систему в первоначальное состояние, выполняем обратные команды и еще раз перезагружаемся:
> BcdEdit /set noIntegrityChecks OFF
> BcdEdit /set loadoptions ENABLE_INTEGRITY_CHECKS
> BcdEdit /set TESTSIGNING OFF
Описание модулей CHIPSEC
Две основные утилиты в CHIPSEC — chipsec_main и chipsec_util. Утилита chipsec_util содержит набор инструментов для взаимодействия с аппаратной платформой. Чтобы просмотреть весь набор функций, предоставляемый данной утилитой, достаточно выполнить команду chipsec_util в командной строке (результат).
Утилита chipsec_main запускает тесты. Чтобы запустить стандартный набор тестов для оценки защищенности аппаратной платформы, выполняем chipsec_main в командной строке (полный лог).
Результат работы chipsec_main
Для запуска отдельного модуля с тестом можно воспользоваться опцией -m или --module.
Запуск модуля common.bios_kbrd_buffer
Полный список опций и формат возвращаемого значения chipsec_main можно посмотреть здесь. Список поддерживаемых CHIPSEC аппаратных платформ — здесь. Если платформа не поддерживается, пользоваться фреймворком все равно можно. В таком случае CHIPSEC пропустит все тесты, специфичные для конкретных аппаратных платформ.
Дополнительные опции 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
В качестве примера использования CHIPSEC в Python был написан скрипт chipsec_script.py. Он запускает определенный набор модулей CHIPSEC и делает вывод о состоянии защищенности аппаратной платформы.
Результат работы скрипта 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 для материнских плат разных производителей обнаруживаютсяоднотипные уязвимости?
- Intel распространяет инструменты для работы с UEFI, содержащие небезопасные дефолтные настройки
- Ошибки допускают независимые разработчики компонентов UEFI (IBV, IHV и ISV)
- По сути, это низкоуровневые бэкдоры, заложенные по требованию сами-знаете-кого
Заключение
UEFI — это root of trust всей электронно-вычислительной системы, и безопасность прошивки UEFI заслуживает отдельного внимания.
Практика показала, что существующие защитные решения и рекомендации по безопасной разработке могут обеспечить должный уровень защищенности компонентов аппаратной платформы, но зачастую производители игнорируют их.
CHIPSEC Framework позволяет понять, насколько прошивка UEFI соответствует рекомендациям по безопасной разработке, а также оценить ее устойчивость перед известными атаками.
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei