
На современном этапе развития вычислительных технологий, вопросы безопасности выходят за рамки уязвимостей операционных систем (ОС) и ошибок программного обеспечения. В глубине всех абстракций процессоры развивали сложные микроархитектуры — конвейеры, кеши, буферы и исполнительные механизмы, спроектированные для достижения максимальной производительности. С иронией, подобные особенности вводят новые и тонкие риски для безопасности, порождая так называемые микроархитектурные атаки. Такие атаки используют непреднамеренное совместное использование и утечку состояния микроархитектуры между одновременно выполняемыми приложениями, иногда даже в совершенно безопасном программном обеспечении.
Этот подробный блог-пост призван развеять мифы о микроархитектурных атаках, освещая:
Это руководство поможет вам понять эти мощные современные атаки и как защититься от них, будь вы новичок, исследователь, разработчик программного обеспечения или специалист по кибербезопасности.
Микроархитектурные атаки — это техники эксплуатации, которые используют непреднамеренные утечки информации в низкоуровневом проектировании аппаратного обеспечения процессора.
В отличие от обычных программных эксплойтов, для микроархитектурных атак не требуются ошибки программирования в приложении или ОС. Вместо этого они используют то, как современные CPU стремятся максимизировать производительность, например, за счет совместного использования кешей или переупорядочивания инструкций.
Современные CPU делят критически важные аппаратные структуры между приложениями и даже виртуальными машинами, такие как:
Поскольку эти структуры не изолированы идеально, часто один процесс может наблюдать или догадываться о воздействиях другого. Злоумышленники используют это неявное совместное использование для извлечения секретов, наблюдая косвенные физические эффекты (например, незначительные изменения времени доступа в памяти).
Существует два широких класса:
Скрытые каналы создают путь передачи данных между двумя участниками (отправителем и получателем), не предусмотренный системой. Одно приложение модулирует некоторый общий ресурс, в то время как другое наблюдает за этими изменениями, чтобы восстановить сообщение.
Примеры:
Атаки, использующие сторонние каналы, утечают конфиденциальную информацию без прямой связи. Вместо этого они используют информацию, «выплеснутую» активностью жертвы.
Примеры:
Оба канала позволяют одному процессу выводить информацию о другом, иногда через пределы контейнера, виртуальной машины или пользователей.
Гетерогенные вычислительные системы включают несколько типов процессоров (общего назначения CPU, GPU, FPGA, AI акселераторы и т.д.) в одной платформе, часто делящие часть памяти и/или состояние микроархитектуры.
Предположим, что GPU и CPU делят регион кеша. Низкопривилегированный процесс, работающий на GPU, может «праймировать» кеш, а высокопривилегированный процесс, работающий на CPU, может невольно раскрывать секреты через свои обращения к памяти. Тогда низкопривилегированный процесс может наблюдать изменения, делая выводы о защищенной информации.
RISC-V является открытой, модульной системой команд, быстро набирающей популярность для исследований и коммерческих встроенных систем. Хотя микроархитектурные атаки хорошо изучены на x86 и ARM, новейшие исследования показывают, что RISC-V также уязвим.
Ключевой вывод: Ни одна система команд или открытое аппаратное обеспечение не защищены — все CPU с общей микроархитектурой уязвимы, если они не были специально защищены.
Новая область: атаки на стековый движок (Источник)
Если атакующий и жертва делят CPU, проводя тщательные операции со стеком и наблюдая за получающимися временными характеристиками, атакующий может выводить какую-то активность со стеком жертвы немного ранее.
Spectre и Meltdown (2018) показали миру, что микроархитектурные атаки больше не теория — они затрагивают миллиарды компьютеров.
[Процесс жертвы] [Процесс атакующего]
Выполняет инструкцию Наполняет кеш, измеряет времена доступа
над секретными данными Расшифровывает изменения благодаря активности жертвы
---[Физически делится кешом]---
Prime+Probe — классическая атака, работающая следующим образом:
Как разместить монеты на всех сиденьях в театре (наполнение), чтобы кто-то другой вошел (жертва), а затем проверять, какие сиденья пусты (проверка) — выявление, где сидела жертва, без прямого наблюдения за ней.
Недавние атаки нацелены на оптимизацию стекового движка:
Важно подчеркнуть: практические атаки на работающие системы незаконны без согласия. Однако, выполнение измерений производительности, выявляющих временные сторонние каналы, можно проводить на собственных тестовых машинах для исследований и защиты.
Простой временной пробник для проверки совместного использования кеша (например, в виртуальных машинах).
#!/bin/bash
buffer=/tmp/testmem
size=1024000
# Выделение большого буфера
dd if=/dev/urandom of="$buffer" bs=1K count=1000
# Многократный доступ к памяти для "прайма" кеша
function prime_cache {
for i in $(seq 1 $size); do
tail -c +$i "$buffer" | head -c 1 >/dev/null
done
}
# Измерение времени доступа
function time_access {
/usr/bin/time -f "%e" dd if="$buffer" of=/dev/null bs=1K count=1000 2>&1
}
echo "Праймирование кеша..."
prime_cache
echo "Измерение времени чтения..."
time_access
# Теперь попросите другой процесс запустить нагрузочную задачу с памятью и повторите
# Сравните, чтобы увидеть, изменилось ли время, указывая на конкуренцию кеша!
Анализируйте значительные изменения как признак конкуренции с другими процессами, потенциально позволяя атаки Prime+Probe.
Более точный метод использует модуль time в Python и массивы numpy для повторяющихся паттернов доступа к памяти.
import numpy as np
import time
# Выделение большого массива
arr = np.zeros((1024 * 1024 * 10,), dtype=np.uint8)
def probe_access():
ts = time.time()
# Доступ ко всем элементам, чтобы принудить загрузку кеша
for i in range(0, len(arr), 64):
arr[i] += 1
te = time.time()
print(f"Время доступа: {te - ts:.6f} секунд")
# Первый запуск: должен быть холодным (возможны ошибки страничного обращения)
probe_access()
# Второй запуск: кеш вероятно горячий
probe_access()
Теперь, во втором терминале (или отдельном процессе), запустите сценарий с большим использованием памяти (например, stress-ng или подобный), который будет вытеснять кеш-линии. Запустите probe_access() еще раз и наблюдайте увеличение времени.
Если вы видите увеличение времени доступа после того, как другой процесс работает, это означает, что кеш вашей системы уязвим к временным атакам.
Учитывая постоянство микроархитектурных атак, что могут делать защитники безопасности?
# Проверка связанных с сбросом особенностей CPU
grep . /proc/cpuinfo | grep -E 'flush|clflush|clwb'
# Может показать: clflush, указывая на доступные инструкции для программного обеспечения для очистки кешей
Многие поставщики CPU вводят функции, такие как:
Тем не менее, большинство развернутых CPU все еще уязвимы, особенно в облачных средах или с комплексной аппаратурой.
Микроархитектурные атаки уже не "теоретический интерес." По мере того, как наши процесоры становятся более оптимизированными и более общими, тонкости их внутреннего дизайна становятся мощными инструментами в руках опытных злоумышленников.
Особенно в гетерогенных системах, где CPU, GPU и акселераторы делят микроархитектурное состояние, скрытые и стороне каналы не только возможны — они повсеместны. Недавние атаки против процессоров RISC-V и стекового движка подтверждают универсальность и постоянное значение этих рисков, даже для новых архитектур и оптимизаций.
Оставайтесь в курсе, тестируйте собственные среды и требуйте лучшей изоляции — как в программном, так и в аппаратном обеспечении.
Этот пост предназначен только для образовательных целей. Всегда тестируйте в безопасных, контролируемых условиях.
Если вы нашли этот контент ценным, представьте, чего вы могли бы достичь с нашей комплексной 47-недельной элитной обучающей программой. Присоединяйтесь к более чем 1200 студентам, которые изменили свою карьеру с помощью техник Подразделения 8200.