Pull to refresh

О безопасности UEFI, часть вторая

Reading time 9 min
Views 42K
Продолжаем начатый в прошлом посте разговор о безопасности UEFI, об угрозах и имеющихся защитах от них.
В этот раз речь пойдет об SMM, о том, как он устроен и работает, и почему является желанной целью для атаки.
Пропустившим нулевую и первую части сего опуса — рекомендую прочесть сначала их, остальных покорно прошу под кат.

Часть вторая. SMM


Немножечко ликбеза
Информацию о SMM, благодаря специалистам по поисковой оптимизации и сетевому маркетингу (будь они здоровы!), решительно невозможно найти в сети по запросу «SMM», постоянно натыкаешься на предложения что-нибудь увеличить, ускорить и улучшить, поэтому будем проводить ликбез не отходя от снаряда.
System Management Mode — один из наиболее привилегированных режимов исполнения кода у x86/amd64-совместимых процессоров, впервые появившийся в специальной SL-версии Intel 80386. Начиная с 80486 поддерживается всеми x86 CPU, в том числе производства AMD и VIA.
Изначально SMM использовался для независимой от ОС реализации автоматического управления питанием и системными устройствами, т.к. научить этому ОС того времени было сложнее, чем добавить еще один режим исполнения в процессор.
Переход в режим SMM выполняется только при помощи специального прерывания — SMI, которое генерируется различными способами:
— аппаратно, выдачей высокого уровня на вывод SMI#
— самой системой, как результат каких-то событий
— программно, отправкой байта в CPU IO-регистр с заданным номером (чаще всего это регистр 0xB2)

Аппаратное SMI
Писать про него особенно нечего: подаем напряжение на ногу — имеем прерывание. Сейчас используется редко, т.к. почти на всех системах теперь имеются мультифункциональные GPIO, которые могут генерировать события, не прерывая работу ОС, плюс не нужна дополнительная логика для определения, кто же конкретно сгенерировал аппаратное SMI, ведь устройств много, а нога — одна.

Системные SMI
Источников системных SMI может быть довольно много, я перечислю лишь те, которыми можно управлять, включая и отключая их по желанию разработчика прошивки, взяв в качестве примера систему с чипсетом восьмой серии, т.е. с процессором Haswell/Broadwell:
  • xHCI SMI — генерируется USB-контролером, позволяет реализовать эмуляцию legacy USB и загрузку с USB-носителей в DOS
  • ME SMI — генерируется МЕ, позволяет работать с ним системам, которые не имеют нативного драйвера для основного интерфейса ME — HECI
  • GPIO unlock SMI — генерируется при снятии бита Lock с регистров управления выводами GPIO. На этот SMI разработчик прошивки может повесить собственный обработчик, в котором решать, позволять ли ОС управлять конкретным GPIO или нет.
  • Periodic SMI — генерируется чипсетом по внутреннему таймеру с настраиваемой периодичностью в 8/16/23/64 секунды, но обычно он отключен совсем.
  • TCO SMI — генерируется TCO-таймером, если он включен. TCO — это такой Intel-специфичный watchdog-таймер обратного отсчета, который ОС должна взводить каждые несколько секунд, чтобы сообщить watchdog'у, что она в порядке. Если таймер дотикает до нуля, генерируется SMI, в обработчике которого чаще всего происходит перезагрузка системы.
  • EC SMI — генерируется чипсетом при доступе к CPU IO-портам диапазона 0x62-0x66, на котором обычно находится EC, что позволяет наладить его эмуляцию либо защитить его прошивку от записи, к примеру. Чаще всего этот источник отключен и обращение к вышеуказанному диапазону сразу декодируется на шину LPC, куда физический EC и подключен. А если его нет — чипсет отвечает 0xFF на все запросы, и дело с концом.
  • APMC SMI, генерируется при записи в CPU IO-порт APM_CNT, подробнее о нем в следующем разделе.
  • SLP SMI, генерируется при переходе в состояния ACPI S1-S5, точнее при попытке установки бита SLP_EN. С помощью этого прерывания реализуются Sx-ловушки, позволяющие выполнить какой-то платформо-зависимый код перед уходом в сон или гибернацию.
  • IOTR SMI, генерируется при обращении к портам CPU IO. С помощью этого прерывания реализуются IO-ловушки, позволяющие эмулировать legacy-железо, висевшее раньше на IO-портах, т.е. SuperIO, клавиатуру, аудио-чипы, MIDI-, COM- и LPT-порты и некоторые другие вещи. Ваша USB-клавиатура работает в DOS только потому, что обращение к IO-портам 0x60/0x64 перехватывает либо SuperIO, либо IO Trap.
  • И пара-тройка других, о которых тут рассказывать надо слишком долго, всех интересующихся RTFM'ом шлю в даташит.

Программные SMI
Программные SMI генерируются чаще всего либо прошивкой, либо драйверами, но ничего не мешает атакующему с правами администратора в ОС (точнее, необходимы права на исполнение инструкции out) тоже генерировать их.
Программное SMI генерируется при записи в CPU IO-порт APM_CNT (чаще всего это порт 0xB2), в качестве параметра в регистре AL передается его номер. Таким образом, максимальное количество различных обработчиков программных SMI в системе — 256, но реально их от 0-5 на специализированных системах, подготовленных для работы с RTOS, до 15-20 на системах с кучей разного железа, которым надо управлять без вмешательства ОС.

Как реализован SMM
Для кода SMM-диспетчера и обработчиков SMI выделяется 1-3 области физической памяти, которую во всех «обычных» режимах исполнения чипсет помечает как область MMIO с несуществующим устройством, т.е. для всего остального мира эти области — сплошная череда 0xFF, которые невозможно перезаписать. Первая область, называемая обычно ASEG (т.е. «сегмент А»), предназначена для т.н. legacy SMM code, т.е. старых 16-битных обработчиков SMI, которых на современных системах уже нет. Имя сегменту досталось за то, что он находится по фиксированным физическим адресам 0xA0000 — 0xBFFFF. Вторая область с фиксированными адресами — HSEG (т.е. «высокий сегмент»), раньше находилась на 0xFEDA0000 — 0xFEDBFFFF, но на современных системах не используется, т.к. имеется гораздо более удобный сегмент с настраиваемыми адресом и размером — TSEG (т.е. «топовый сегмент»), в котором и находятся сейчас 99% кода, исполняемого в SMM, а в ASEG остается только небольшая заглушка для совместимости.
При переходе в SMM процессор сохраняет практически весь контекст (т.е. содержимое практически всех регистров, какие именно не сохраняются — зависит от конкретной микроархитектуры), причем к сохраненному контексту у обработчиков SMI есть полный доступ, и потому он может общаться с системой через изменение сохраненных значений.
Для ОС вызов SMM кода выглядит как волшебное изменение содержимого регистров и памяти, и хотя отследить длительность нахождения в SMM все же можно по косвенным признакам, а факт перехода в него — по непосредственным, при помощи чтения регистра MSR_SMI_COUNT до и после вызова инициации программного прерывания, но повлиять на длительность обработчика SMI ОС не может, поэтому SMM плохо совместим с hard-RTOS (стоит отметить, что вся архитектура x86 совместима с ними весьма через раз, но это другая история).
При настройках по умолчанию работающий в SMM код имеет полный доступ ко всей физической памяти на чтение и запись, полный доступ ко всем подключенным устройствам, в общем — может практически все, и при этом независим от ОС и недоступен из нее даже на чтение, что сильно затрудняет его анализ и делает код обработчиков SMI весьма привлекательной целью для атаки. Более того, если атакуемой системе доступна из SMM запись на SPI-микросхему (а она доступна во всех случаях, кроме систем с включенной PFAT, которые не найти с огнем, систем с Read-only BIOS'ом, которые встречаются еще реже, и систем с защитой через PR-регистры), то успешная атака может закончиться записью своего кода в BIOS, с последующем воровством, убийством и непотребством с гусями. Именно поэтому защитить SMM от вставки туда вредоносного кода — жизненно необходимо.

Атаки на SMM и защита от них
Забытый D_LOCK
Код в SMRAM не появляется там самостоятельно, сначала саму SMRAM нужно настроить, инициализировать физическую память, настроить TSEG так, чтобы все обработчики туда влезли, скопировать туда код SMM-диспетчера и обработчиков, настроить там таблицы дескрипторов — в общем, навести строгий уставной порядок, после чего обязательно снять бит D_OPEN, чтобы никто больше там ничего не испортил, и установить бит D_LOCK, чтобы D_OPEN нельзя было поставить назад. На некоторых старых системах установить D_LOCK забывали, и там SMM был отрыт всем ветрам, но во времена UEFI этого уже не происходит, так что этот вектор атаки ушел в историю.

SMM cache poisoning
Еще одна историческая атака — отравление кэша SMRAM, которую в 2009 году опубликовали Rafal Wojtczuk и Joanna Rutkowska. Суть атаки коротко — меняем тип памяти для региона SMRAM на Write-Back, организуем запись в регион SMRAM своего кода, запись в память не происходит, но при этом наш код остается в кэше второго уровня, после чего генерируем программное SMI и процессор читает данные не из SMRAM, а из кэша, и выполняет наш вредоносный код. Проблема решилась радикально — производители CPU запретили ставить режим WB на SMRAM, и потому системе с UEFI этой уязвимости не подвержены.

SMM call-out, она же SMM incursion attack
Но достаточно истории, перейдем к «современным» атакам. Начнем, пожалуй, с той самой SMM Incursion Attack, о которой тов. maseal упомянул в комментарии к первой части. Я специально поставил слово «современные» в кавычки, ибо этой атаке — сто лет в обед, впервые о ней сообщали еще в 2008 году как проблему тогдашних BIOS'ов, но в 2015 ее вновь переоткрыли Corey Kallenberg и Xeno Kovah. Атака простая как мычание — если обработчик SMI вызывает какой-либо код, находящийся вне SMRAM, то атакующий с правами на запись в физическую память может подменить вызываемый код на свой, и выполнить его таким образом в режиме SMM. А т.к. разработчики UEFI привыкли к доступности EFI Runtime-сервисов, то эти самые сервисы стабильно вызывались из обработчиков SMI на каждый чих (чаще всего это были вызовы GetVariable, SetVariable и ResetSystem). Уязвимости оказалось подвержено столько систем, что проще сказать, где их не было. По моей грубой оценке, если ваш UEFI старше мая-июня 2015 года по build date, в нем гарантированно имеется пара уязвимых к этой атаке обработчиков SMI. Вычистить систему от таких глючных обработчиков достаточно сложно, и т.к. раньше такое поведение вообще не считалось уязвимостью («какой дурак полезет сервисы хукать то?!») и о том, что так делать нельзя, не было известно простым IBV'шным кодерам — даже сейчас периодически приходят обновления для runtime-драйверов, подверженные этой проблеме. Все очень грустно, в общем.
Для защиты от вызова внешнего по отношению к SMRAM кода инженеры Intel добавили специальный MSR_SMM_FEATURE_CONTROL, после установки определенного бита в котором вызов такого кода генерирует немаскируемое и невосстановимое MCE, но есть такой MSR только в Haswell и более новых CPU, да и включается эта возможность только на время отладки прошивки, иначе за непонятные зависания на ровном месте пользователи могут к дверям отдела R&D прийти с вилами и дубьем — большинству нужно, чтобы работало и сейчас, а эта ваша безопасность вся — overhyped. Для обладателей более старых систем и систем на базе процессоров AMD инженеры Phoenix нашли по своему гениальное решение — использовать NX-бит, настроив память для SMM-кода таким образом, чтобы вызов кода вне SMRAM заканчивался Page Fault'ом, который затем можно обработать, а не висеть намертво на MCE. Каюсь, я у себя пока еще это решение не внедрил, но когда дойдут руки — обязательно это сделаю.
Простому же пользователю от этой атаки можно защититься только не допуская исполнение непонятного кода от рута, но это, к сожалению, на современных ОС практически нереально — вариантов локального повышения прав как было море, так и остается, сколько таких 0day-эксплоитов на руках и в обороте, сказать невозможно. Остается только процитировать вышеупомянутого Xeno Kovah:
Please, please, please, go apply patches!

DMA attack
Еще одна интересная атака, на этот раз — с помощью своего же чипсета. Дело в том, что у современных чипсетов имеется контролер DMA, который используется для разгрузки CPU от задач пересылки данных из памяти и в память, как между DRAM, так и между DRAM и памятью PCIe-устройств. Причем инициировать такую передачу может как ОС, так и PCIe-устройство, у которого тоже может быть свой DMA-контролер. Причем, в случае инициации из ОС, операцию доступа к данным осуществляет чипсет, т.е. любые настройки процессора на него если и влияют, то достаточно слабо. Т.е. атакующий с правами администратора инициирует DMA с контролируемой им областью памяти с одной стороны и SMRAM с другой, и получает полный доступ к ней. То же самое может сделать и прошивка контролируемого атакующим PCIe-устройства. Для защиты от DMA-атаки у DMA-контролеров Intel имеется регистр TSEGMB в котором дублируется информация о местонахождении TSEG, и бит Lock, который запрещает это самое содержимое менять. Если авторы прошивки забыли установить (или восстановить при старте после S3, но об этом — в следующей части) — можно атаковать. Я не знаю, есть ли защита от DMA-атаки у чипсетов AMD, но постараюсь выяснить это в ближайшее время.

SMM cross-buffer attack
Представленная специалистами из Intel ATR атака на обработчики SMI, которые принимают в качестве параметра указатель и размер буфера, и производят запись в него. Атакующий может передать указатель и размер таким образом, чтобы буфер пересекал границу RAM-SMRAM, а т.к. обработчик SMI имеет доступ к SMRAM, то он перепишет какую-то часть данных вначале SMRAM. При удачном стечении обстоятельств (т.е. приблизительно после 500 часов отладки минимум) обработчик может переписать служебные структуры диспетчера SMM или других обработчиков нужным атакующему образом, и он получит возможность выполнения произвольного SMM-кода. Атака адски сложная и целевая, но вполне возможная, поэтому с начала 2015 года все обработчики SMI, принимающие указатели на буфер, обязаны валидировать его перед использованием. На более старых системах атака будет работать, но вероятность того, что именно вас через нее взломают — невелика.

Заключение


Ну вот, теперь разобрались более или менее и с SMM, в следующей части поговорим об атаках на S3 BootScript.
Спасибо за внимание, безопасных вам прошивок.

P.S.
Не могу не поблагодарить тов. d_olex за его статьи об SMM и атаках на него — раз и два. Для интересующихся темой и умеющих читать по-английски — обе обязательны к прочтению.
Tags:
Hubs:
+33
Comments 12
Comments Comments 12

Articles