Расширенный

Расширенный поиск

Автор

Статьи по теме: «Информационная безопасность»

Чем опасны процессорные уязвимости. Часть 1: Атаки по побочным каналам

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

Содержание:

Введение

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

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

Процессорные ошибки

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

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

Выявление недостатка в процессоре – явление нечастое и необычное, поэтому факт его обнаружения как правило получает широкую огласку, что сильно усугубляет положение компании-производителя. Яркий пример этого – ошибка Pentium FDIV bug, недостаток в модуле вычислений с плавающей точкой в процессорах Intel Pentium, обнаруженная профессором Линчбургского колледжа Томасом Найсли в октябре 1994 г.

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

Наращивание производительности и безопасность в процессорах

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

Основные пути повышения производительности – это увеличение плотности транзисторов на кристалле процессора и увеличение тактовой частоты. Это, хоть и ускоряет выполнение инструкций, может не дать желаемого прироста, так как не избавляет от основной проблемы – простоя процессора при обращении к ОЗУ и другой периферии, медленным по сравнению с процессором. Более того, повышение тактовой частоты и наращивание числа транзисторов имеют свои ограничения при текущем технологическом процессе: первое приводит к перегреву чипа, и второе жестко лимитировано физикой и доступными материалами.

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

Кэш-память

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

Для выравнивания разрыва в скорости работы центрального процессора и ОЗУ применяется иерархическая организация памяти, идея которой была предложена еще в 1946 г. Артуром Бёрксом, Германом Голдстайном и Джоном фон Нейманом. Вместо использования исключительно ОЗУ, между ним и вычислительным устройством помещается несколько более быстрых запоминающих устройств, называемых кэшами.

Кэши хранят в себе результаты прошлых операций: копии данных (или инструкций), загруженных из оперативной памяти, либо же результаты вычислений. При необходимости получения данных из ОЗУ, ЦП сначала по очереди проверяет все уровни кэш-памяти, один за другим, на наличие необходимых данных и, только если данных там не нашлось, обращается к ОЗУ. Современные процессоры используют три уровня кэш-памяти, каждый из которых расположен непосредственно на чипе. Объем и скорость кэш-памяти стали одними из основных процессорных характеристик.

Кэши первого уровня (L1, level 1) находятся на каждом из ядер процессора и подразделяются на: L1d (для данных) и L1i (для инструкций). Время доступа к этому кэшу самое малое, но и информации он вмещает в себя меньше остальных.

Кэш второго уровня (L2, level 2) также в большинстве современных процессоров размещается на ядре, но не подразделяется на данные и инструкции. Он больше и медленнее кэша L1.

Кэш третьего уровня (L3, level 3 или LLC, last level cache) – общий для всех ядер. Он значительно объемнее предыдущих уровней, но и время доступа к нему больше.

Кэш четвертого уровня в современных процессорах обычно не применяется.

Кроме этих кэшей есть еще и кэши специального назначения. Среди них – буфер ассоциативной трансляции (Translation lookaside buffer, TLB), служащий для сохранения информации о трансляции виртуальных адресов в физические.

Кэш-память успешно сглаживает разрыв в скорости работы ОЗУ и ЦП, избавляет от повторения уже выполненных операций. Но при этом текущая реализация ослабляет изоляцию процессов. Данные процессов в оперативной памяти строго изолированы друг от друга, и за проверку доступа к ним отвечают как операционная система, так и сам процессор. Непривилегированный процесс не может считывать или изменять память другого процесса. Для кэшей же разделение памяти не предусматривалось, ведь программа не может явно проверить содержимое кэша или считать оттуда произвольные данные. Процессор не предоставляет таких возможностей. Поэтому данные различных пользовательских процессов, а также процессов ядра ОС, соседствуют в кэше, и никак друг от друга не отделены. Более того, каждому процессу во время его работы кэш предоставляется целиком, со всеми данными других процессов. Далее будет рассмотрено, как это позволяет злоумышленнику извлекать данные других пользователей и ядра ОС из оперативной памяти.

Внеочередное исполнение

В том или ином виде внеочередное исполнение реализовано во всех современных процессорах, так как позволяет получить наибольший выигрыш в производительности за счет параллелизма на уровне команд. Intel стала использовать внеочередное исполнение в процессорах Pentium Pro в 1995 г. Вместо строгого исполнения инструкций в порядке, представленном в программе, механизм внеочередного исполнения меняет порядок инструкций для минимизации времени простоя процессора. Для переупорядочивания инструкций применяется алгоритм Томасуло, который позволяет избежать конфликтов и нарушения целостности информации. Команды выстраиваются в очередь и исполняются по мере готовности своих операндов, не обязательно следуя порядку в программе. Рассмотрим следующий пример:

ld  → r1, 0(r2)  → // загрузить r1 из адреса r2
add → r2, r1, r3 → // r2 := r1 + r3
add → r4, r3, r5 → // r4 := r3 + r5

Предположим, что операнды r3 и r5 готовы к использованию, в то время как r1 должен быть загружен из оперативной памяти. При поочередном исполнении инструкций для выполнения первой команды процессор останавливается, ожидая готовности операнда (загрузки из оперативной памяти). Но для выполнения третьей инструкции данные в r1 не требуются, а ее операнды готовы к использованию. При внеочередном исполнении эта команда выполнилась бы первой, в то время пока подготавливается операнд для инструкции загрузки данных из памяти. Заметим, что внеочередное исполнение второй команды невозможно, так как она явно зависит от результатов первой.

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

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

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

Спекулятивное исполнение

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

for (i = 0; i < limit; i++)
     results[i] = data;

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

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

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

Одновременная многопоточность

Одновременная многопоточность – развитие идеи суперскалярной архитектуры процессора, то есть дублирования некоторых компонентов для исполнения нескольких задач одновременно. Современные процессоры допускают выполнение нескольких программ на одном ядре процессора одновременно, за счет дублирующих элементов конвейера процессора. Для операционной системы это выглядит как работа двух различных логических ядер.

Для одновременной многопоточности требуется дублирование элементов процессорного конвейера, но не требуется разделение кэшей и микроархитектурных буферов. Как будет показано далее, совместное использование кэшей и буферов соседствующими на ядре потоками приводит к нарушению изоляции и грозит компрометацией данных. Именно совместное использование делает уязвимой реализацию одновременной многопоточности Intel Hyper-Threading.

Эксплуатация процессорных уязвимостей

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

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

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

Далее мы еще вернемся к вопросу применимости атак на процессоры при обсуждении уязвимостей, основанных на упреждающем исполнении.

Атаки по побочным каналам

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

Рассмотрим следующий пример:

if (read_secret() == "secret") {
          quickly_computed_operation(); // Эта операция осуществляется быстро
} else {
          slowly_computed_operation(); // Эта операция осуществляется медленно
}

Предположим, что в коде программы встречается приведенный выше участок. Поскольку одна из ветвей выполняется значительно дольше другой, злоумышленник может, замерив время работы программы, определить, было условие выполнено или нет. Для данного примера определить, что условие выполняется, равносильно полному раскрытию секрета. Если время работы программы сравнительно небольшое, то секрет будет равен "secret".

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

Атаки по побочным каналам - не редкость в современных условиях, и имеют практическое применение. К атакам по побочным каналам оказались уязвимы как программные продукты (например, OpenSSL и Keyczar), так и аппаратные. Как мы увидим далее, современные процессоры не стали исключением.

Типы атак по сторонним каналам

Атаки по побочным каналам типизируются по трем основным характеристикам: контролю над вычислительным процессом, способу доступа к системе и методам, используемым в процессе анализа.

Контроль над вычислительным процессом

По данной характеристике атаки разделяют на пассивные и активные.

В случае пассивной атаки, атакующий не влияет на работу системы. Он собирает информацию о работе системы, но при этом процесс исполнения протекает точно так же, как если бы атака не проводилась.

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

Способ доступа к системе

По данному параметру атаки делятся на инвазивные, полуинвазивные и неинвазивные.

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

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

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

Методы анализа

Методы проведения анализа делят на простые и дифференциальные.

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

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

Виды атак по побочным каналам

Наиболее часто атака по побочным каналам использует всего один такой канал, поэтому атаки удобно разделять по типу используемого канала. Далее мы рассмотрим известные (на момент написания статьи) виды атак.

Атака по времени

Данный тип атак основан на нахождении корреляции между используемыми операцией секретными данными и временем проведения операции.

Для проведения такой атаки требуется выполнение следующих условий:

  1. Время выполнения операции должно зависеть от секретных данных.
  2. Есть возможность производить ряд замеров, при этом секрет должен оставаться неизменным.
  3. Доступно достаточно точное средство замера времени.

Пример уязвимой к данной атаке программы приведен выше.

Именно эта атака по времени нас будет интересовать больше всего, ведь ее вариация повсеместно используется при эксплуатации процессорных недостатков. Атака по побочным на кэши – эффектный метод восстановления содержимого кэша процессора или же определения зон памяти, затронутых другим процессом. Разновидности атак на кэши (FLUSH+RELOAD, EVICT+RELOAD, PRIME+PROBE и т.д.) концептуально одинаковы, они различаются лишь требованиями и ограничениями. В общем случае атака на кэши проводится следующим образом:

  1. Кэш очищается от данных. Это можно сделать, используя инструкцию процессора, либо просто записав достаточно большой массив данных в память, который вытеснит все содержимое кэша.
  2. Замеряется время доступа к интересующему участку в памяти (заметим, что данные будут считываться из основной памяти, а не из кэша).
  3. Запускается исследуемая операция (или выжидается момент, когда проработает атакуемый процесс).
  4. Вновь замеряется время доступа к интересующему участку.
  5. Если разница во времени доступа достаточно велика, то исследуемая операция использовала данный участок, и потому данные оказались в кэше, что и привело к различию во времени доступа.

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

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

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

Защитившись от атак по времени, вы устраняете побочный канал. Для этого можно:

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

Атака на основе сбоев

Это активная атака, при которой злоумышленник вызывает ошибки в работе алгоритма, за счет чего меняется выходное значение. В некоторых случаях это позволяет восстановить используемый секрет. В таких атаках наиболее важно определить:
  • с какой точностью возможно выбрать время и место возникновения ошибки;
  • какая порция данных будет затронута: байт, бит и т.п.;
  • постоянство ошибки; переменная ли ошибка или постоянная;
  • как себя проявляет сбой: изменяется значение бит с 0 на 1, байт меняется случайным образом и т.д.

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

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

Атака анализа энергопотребления

Атака в некотором смысле схожа с атакой по времени. Злоумышленник замеряет энергопотребление устройства и по нему определяет проводимые операции и параметры.

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

Тем не менее, примеров этой атаки на процессоры пока нет, а используется она в основном для атак на аппаратные криптосистемы.

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

Считывание остаточной информации

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

Интересный пример - атака Cold boot attack, при которой устройство перезагружается без вмешательства ОС (например, отключением и восстановлением питания) и считываются данные из неочищенной оперативной памяти.

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

Другие виды атак

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

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

Уязвимости процессоров, вызванные наличием стороннего канала

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

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

Ряд атак по побочному каналу через кэш осуществляются так: по изменениям в кэше определяются производимые жертвой действия и, если они определяются секретными данными, эти действия дадут атакующему преставление о секрете.

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

TLBleed

На данный момент известно множество атак на кэши L1, L2 и LLC, и от них были созданы защитные механизмы, например, Intel CAT. Но, как указывалось ранее, существуют кэши специального назначения, в частности, кэш TLB, хранящий результаты трансляции адресов памяти.

TLB - один из ресурсов, разделяемых потоками на одном ядре, поэтому поток может отслеживать по изменениям в данном кэше действия своего соседа. Для этого замеряется время доступа к определенным адресам в памяти. Если доступ производится сравнительно быстро, то адрес уже находится в TLB, а значит и соседствующий поток его использовал.

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

Такая атака может быть эффективна в рамках облачной инфраструктуры, где процессы различных пользователей выполняются на одном процессоре, и часто используется Hyper-Threading.

NetCAT (CVE-2019-11184)

Данная атака проанализирована специалистами Vrije Universiteit Amsterdam. Уязвимость получила оценку в 4.8 баллов из 10. В основе атаки лежит механизм Intel Data-Direct I/O (DDIO), позволяющий серверным процессорам сократить время обработки входящих пакетов за счет записи данных напрямую в кэш последнего уровня, а не в основную память. Это ускоряет время обработки данных, так как не требует продолжительной загрузки данных процессором. С другой же стороны, это делает кэш доступным для удаленного злоумышленника, причем исполнение кода локально не требуется. Именно это и эксплуатирует NetCAT: обновления в кэше отслеживаются удаленно, что позволяет провести атаку в рамках сети, а не только одного устройства. Такая схема не требует особых знаний о машине жертвы, за исключением модели процессора.

У атаки есть следующие ограничения: во-первых, на атакуемом сервере должен быть включен механизм DDIO; во-вторых, с сервером должно быть установлено соединение RDMA (это механизм удаленного доступа к памяти).

Причина первого ограничения ясна: если механизм DDIO не включен, провести сетевую атаку нельзя. Второе ограничение связано с требованием к точности замеров времени и доступа к удаленной памяти. Для успешной атаки злоумышленник должен хотя бы частично контролировать то, куда будут записаны его данные, и откуда они будут считаны. Механизм RDMA позволяет удаленному устройству напрямую перезаписывать или считывать заранее одобренные и зарегистрированные области памяти сервера. RDMA встречается в суперкомпьютерных комплексах и дата-центрах, что сужает область применения атаки.

Авторы работы отмечают возможность использования NetCAT для построения скрытого канала сообщения и для кражи данных пользователя из SSH сессии. Краже данных способствует то, что протокол telnet, используемый в SSH, подразумевает отправку пакета данных на сервер при каждом нажатии клавиши пользователем. Восстановив время прихода пакетов через обновления в кэше, злоумышленник сможет определить последовательность нажатий методами машинного обучения и, в результате, узнать секреты пользователя.

Атака представляет серьезную опасность, но подвержена изменениям в сети, например, высокой загрузке. На момент написания статьи нет свободно доступной программной реализации данной атаки, поэтому от атакующего требуется знание методов атак на кэши и работы с RDMA.

PlunderVolt (CVE-2019-11157)

Ранее мы познакомились с атаками, проводимыми через кэш. Таких атак большинство, но есть и другие, использующие побочные каналы не по времени, а, например, по ошибкам вычислений. Данная атака относится именно к таким.

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

Атака направлена на Intel Software Guard Extensions (SGX), систему, позволяющую создавать защищенные анклавы, то есть области памяти для кода и данных. Данная технология позволяет избежать порчи и чтения данных от злоумышленника с наивысшим уровнем доступа в операционной системе. Память анклава защищена криптографическими инструментами, проводится контроль целостности данных, а чтение данных из защищенной области (даже при наличии привилегии) всегда возвращает константное значение.

Однако, понижая напряжение, злоумышленник может вызвать предсказуемые ошибки в работе кода анклава. Важно, что эти ошибки происходят до записи данных в память анклава, поэтому проверка целостности не помогает распознать атаку.

Plundervolt позволяет восстановить ключи шифрования, используемые анклавом, при помощи атаки Bellcore в случае использования RSA-CRT (подписи и расшифровывания), дифференциального анализа ошибок (differential fault analysis, DFA) при использовании аппаратного шифрования AES, а также позволяет нарушить генерацию новых ключей.

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

Plundervolt – требовательная к ресурсам атака, для ее проведения нужны высокие привилегии и возможность исполнения кода на системе. Кроме того, уровень напряжения для атаки определяется температурой процессора. Тем не менее, это серьезная угроза для анклавных приложений, которая требует мер защиты. Уязвимость получила оценку в 6.7 баллов, что делает ее достаточно опасной.

Очевидная мера предупреждения атаки – ужесточение правил использования интерфейса управления напряжением. Он может быть отключен в целом или же ограничен безопасными значениями частоты и напряжения. Кроме этого, возможно отменять данную настройку при входе в анклав, перепроверять полученные в анклавах значения, а также использовать алгоритмы, стойкие к возникновению ошибок (например, результат RSA-CRT может перепроверяться без проведения операции заново). Для устранения данной уязвимости Intel предоставила обновления микрокода.

Заключение

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

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

Авторы:
Григорий Дороднов, исследователь безопасности, ООО «СолидСофт»,
Денис Гамаюнов, зав. лабораторией интеллектуальных систем кибербезопасности, ВМК МГУ имени М.В. Ломоносова