Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
smiiiiiiiiiiiiiiii — Очень очень очень очень очень очень очень длинное прерывание | Kitploit
Инструменты/GitHubGitHub/xoreaxeaxeax/smiiiiiiiiiiiiiiii
Анализ уязвимостейЭксплуатацияАппаратный ХакингАппаратная Безопасность
GitHubxoreaxeaxeax/smiiiiiiiiiiiiiiii

smiiiiiiiiiiiiiiii

Очень очень очень очень очень очень очень длинное прерывание

Репозиторий
1585622 дней назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

smiiiiiiiiiiiiiiii

Эксплуатация System Management Mode с помощью очень очень очень очень очень очень очень длинного прерывания.

Обзор

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

SMM требует, чтобы все ядра одновременно находились либо в SMM, либо вне SMM. Его модель безопасности не работает без этого — когда один поток входит в SMM, это заставляет все остальные тоже войти.

Чтобы сломать это, нам нужен кто-то, кто слишком занят, чтобы заметить, что он должен присоединиться к SMM.

Это работает примерно так:

root@kitploit:~
core 0 - start a long instruction
       |
       |
       |
core 1 - invite core 0 to smm
       |
       |
       |
core 1 - enter smm
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - wait for core 0
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
       |
core 1 - give up
core 1 - do secret smm stuff
core 1 - finish smm
       |
       |
       |
core 0 - join smm

В этот момент core 1 находится вне SMM, а core 0 — внутри, что позволяет core 1 атаковать core 0. Вот загвоздка: для этого нам нужна очень, очень, ооочень длинная инструкция — длиннее, чем любая инструкция когда-либо должна была выполняться. Большинство машинных инструкций на современном CPU быстрые: add занимает 1 цикл. Чтобы заставить core 1 отказаться от ожидания core 0, нам нужна инструкция на core 0, которая занимает около 4 000 000 000 циклов — более 1 секунды реального времени.

Тайм-аут в одну секунду

Прошивка x86 выполняет следующий код когда ядро CPU входит в SMM:

root@kitploit:~
  for (Timer = StartSyncTimer ();
       !IsSyncTimerTimeout (Timer, mTimeoutTicker) && SyncNeeded;
       )
  {
    mSmmMpSyncData->AllApArrivedWithException = AllCpusInSmmExceptBlockedDisabled ();
    if (mSmmMpSyncData->AllApArrivedWithException) {
      break;
    }

    CpuPause ();
  }

Код ожидает, пока все ядра войдут в SMM, или до 1 секунды, в зависимости от того, что произойдёт раньше. Чтобы заставить одно ядро выполнять код SMM, пока другое ядро продолжает выполняться вне SMM, нам нужно, чтобы это внешнее ядро оставалось непрерываемым в течение всей секунды — SMI обрабатывается на границе инструкции, поэтому любой разрыв между двумя инструкциями позволяет ожидающему SMI втянуть ядро в SMM. Поэтому задержка должна быть одной инструкцией: одной непрерываемой операцией, которая переживёт односекундный сбор.

Proof-of-Concept

Существует множество способов достичь запретной 1-секундной инструкции, и точный подход будет различаться от платформы к платформе. Но, в общем: найдите адрес MMIO с высокой задержкой, а затем убедите CPU читать с него как можно медленнее — злоупотребите недокументированной областью, которая отвечает на чтения крайне медленно, используйте самую широкую загрузку, которую даёт ISA, чтобы переместить как можно больше байтов через неё за одну инструкцию, и позвольте другим ядрам конкурировать за ту же шину, чтобы замедлить её ещё больше. Одно чтение, одна инструкция — и CPU застревает, удерживая её почти целую секунду.

Предоставленный proof-of-concept настроен для Zen 3 Ryzen 7 5800H, где широкая загрузка xmm из медленного MMIO по адресу 0xfcc68860 зависает достаточно долго, чтобы сломать сбор всех ядер:

root@kitploit:~
mov     $0xfcc68860, %rsi   ; the target MMIO address
vmovdqu (%rsi), %xmm0       ; the very, very long load

PoC эксплуатирует это, сталкивая два ядра друг с другом. Одно ядро удерживается вне SMM длинной инструкцией — тесным циклом на очень медленной загрузке:

root@kitploit:~
/* the victim core: spin on the ~1-second load, too busy to answer the SMI */
for (;;)
    asm volatile ("vmovdqu (%0), %%xmm0" :: "r"(mmio) : "xmm0");

Тем временем другое ядро настраивает счётчики SMI для каждого ядра:

root@kitploit:~
#define MSR_PERF_CTL0  0xc0010200        /* AMD core perf event-select MSR */
#define MSR_PERF_CTR0  0xc0010201        /* the paired 48-bit counter      */

for (int cpu = 0; cpu < ACTIVE_CPUS; cpu++) {
    msr_write(cpu, MSR_PERF_CTL0, 0x43002b);  /* EN | OS | USR | event 0x2b */
    msr_write(cpu, MSR_PERF_CTR0, 0);         /* zero the count            */
}

Затем запускает шквал SMI:

root@kitploit:~
asm volatile ("outb %%al, $0xb2" :: "a"(0));  /* kick port 0xb2 -> #SMI    */

И считывает итоги каждого ядра:

root@kitploit:~
/* ...fire the storm, then read every core's tally back... */
uint64_t delta = smi_max - smi_min;
if (delta)
    puts("!!! a core ran outside SMM");

Если счётчики расходятся, это означает, что одно ядро продолжало выполняться вне SMM, пока остальные были втянуты внутрь — оно пропустило SMI, которые обслуживали остальные.

Чтобы лучше это проиллюстрировать, мы можем запустить proof-of-concept за безвкусно кричащим и совершенно бесполезным GUI, отслеживающим счётчики SMI на каждом ядре, чтобы наблюдать, как они выполняются в идеальной синхронизации, пока сильно задержанное ядро не нарушит их требуемую синхронизацию:

SMI counter divergence in action

Единственная гарантия SMM — что ничего больше не выполняется, пока он работает — рушится под одной-единственной абсурдно длинной инструкцией.

Эксплуатация

Безопасность SMM опирается на простое допущение: пока он выполняется, больше ничего не выполняется.

Вот есть 100+ SMM TOCTOU CVE наружу там: обработчик SMM проверяет значение в общей памяти, затем использует его. Всё, что нужно для эксплуатации — перезаписать это значение между проверкой и использованием, и вы внутри SMM. Но эти проблемы лежат спящими и в основном неисправленными в реальном мире из-за одного допущения: эксплуатация требует, чтобы кто-то модифицировал общую память пока выполняется SMM, а из-за сбора SMM ни одно ядро CPU не находится вне SMM, чтобы запустить атаку. Единственный путь внутрь — периферийное устройство с DMA, записывающее за спиной CPU — физический доступ, вредоносное устройство — поэтому весь класс списывается как аппаратная проблема.

Десинхронизация SMI устраняет предпосылку, которая обеспечивала безопасность платформы: внешнее ядро, без физического доступа или аппаратного обеспечения, теперь может выполняться, пока выполняется SMM — и спящие CVE становятся эксплуатируемыми из программного обеспечения.

Меры смягчения

Их, вероятно, не существует, что делает эту проблему несколько более интересной, чем традиционные проблемы SMM. Оставьте тайм-аут — и сбор легко ломается. Уберите тайм-аут — и легитимно застрявшее ядро повесит платформу на первом же SMI. Увеличьте тайм-аут — и вы убьёте производительность на многоядерных платформах, которые вынуждены останавливать все ядра при каждом входе в SMM. Неясно, каков лучший путь вперёд, или существует ли он вообще.

А пока рекомендуемый обходной путь — не выполнять никаких длинных инструкций.

Перенос на вашу платформу

Стандартная vmovdqu по адресу 0xfcc68860 в proof-of-concept — медленное место на этой машине — Zen 3 Ryzen 7 5800H — и, скорее всего, нигде больше. Чтобы сломать сбор на вашей машине, вам нужно перенастроить длинную инструкцию так, чтобы задержка пережила ваш тайм-аут SMM. Несколько советов, как это сделать:

  1. Нацельтесь на свой MMIO. Найдите медленную область MMIO на вашей платформе с помощью mmiotic.
  2. Расширьте чтение. Шагайте -r xmm → ymm → zmm, пока задержка не пересечёт тайм-аут сбора.
  3. Замените инструкцию. Если ни одно чтение MMIO не достаточно медленное, вам нужна другая патологически длинная инструкция; asm-hall-of-shame показывает, как их находить.

Сборка

root@kitploit:~
make          # builds smiiiiiiiiiiiiiiii

Использование

Значения по умолчанию настроены под одну машину. На чём угодно, кроме Zen 3 Ryzen 7 5800H, не ожидайте расхождения, пока вы не перенастроите длинную инструкцию — см. Перенос на вашу платформу.

Запустите инструмент, чтобы многократно запускать очень-очень длинную инструкцию, наблюдая за счётчиком SMI каждого ядра на предмет расхождения:

root@kitploit:~
sudo ./smiiiiiiiiiiiiiiii          # default: -r xmm at 0xfcc68860

Флаги:

ФлагПо умолчаниюОписание
-r xmm|ymm|zmmxmmШирина векторного регистра для замеряемого чтения MMIO (16/32/64 байта). Если расхождения счётчика SMI не наблюдается, инструмент советует перейти к следующему размеру.
-a <phys-addr>0xfcc68860Целевой физический адрес для цикла замера MMIO (шестнадцатеричный 0x... или десятичный).
-h, --help—Вывести справку и выйти.

Ссылки

  • DEF CON 2026 – Weaponizing Uselessness

Автор

smiiiiiiiiiiiiiiii — исследовательский проект Кристофера Домаса (@xoreaxeaxeax).

Скачать инструмент