V12 скомпрометировала SGX-анклав службы поиска контактов Signal и извлекла закрытый ключ
Contact Discovery Service (CDSI) в Signal сверяет адресную книгу пользователя со списком зарегистрированных абонентов, не раскрывая её серверу. Обработка идёт внутри Intel SGX-анклава: память зашифрована, а исходное состояние анклава заверяется аттестацией, которую клиент может проверить. Приложение выгружает контакты автоматически, каждые 48 часов, по умолчанию - на Android и iOS. Signal широко распространён, в том числе как полевое средство связи у противника, поэтому модель доверия CDSI представляет практический интерес.
Ключевой момент модели угроз: SGX защищает анклав от оператора машины, но сам оператор (недоверенный хост) по-прежнему управляет запуском потоков, таблицами страниц и временем жизни объектов. Снимая бит доступа со страницы, хост вызывает страничный отказ в нужной точке кода и останавливает поток анклава. Это превращает редкие состояния гонки в детерминированные и упрощает раскладку кучи.
Найдено две ошибки времени жизни объектов.
Первая - дублирование обработчика шарда. Ради быстродействия база разбита на шарды, каждый обслуживает свой поток-обработчик. Протокол исходит из того, что обработчик один: запрос ставит в очередь чтение, затем ожидание, и завершение ожидания служит признаком, что чтение закончено и буфер результата можно освободить. Анклав не проверял, есть ли уже обработчик у шарда, - и допускал запуск второго. Тогда ожидание снимает один поток, пока другой ещё пишет результат: запись уходит в уже освобождённую память. Через раскладку кучи освобождённый буфер переиспользуется как поле protobuf (указатель + длина), и штатный кодировщик ответа копирует наружу выбранный диапазон. Итог - произвольное чтение памяти анклава, которым извлекается 32-байтовый закрытый ключ ответчика Noise.
Вторая - гонка проверки и использования дескриптора клиента (TOCTOU). Клиентское соединение представлено объектом с секретным маркером (canary); анклав сначала сверяет маркер, затем отдельной атомарной операцией помечает объект занятым. Между этими шагами хост тем же страничным отказом останавливает поток, освобождает клиента, раскладывает кучу и подставляет по тому же адресу свой объект. Проверку прошёл настоящий клиент - работа идёт уже с подставным. В объекте лежат указатели на шифрующее состояние Noise; хост направляет их в свою память и подсовывает указатель на код восстановления регистров Open Enclave с готовым набором регистров. При попытке зашифровать ответ анклав передаёт управление по этому указателю - хост получает контроль над регистрами и исполнение кода в доверенном контексте. В PoC это вызов memcpy, который выносит закрытый ключ наружу.
Оба PoC проверены на том же типе Azure-машин с SGX, что стоит у Signal в проде, на официальной сборке анклава с ожидаемым MRENCLAVE. Доказательство подлинности компрометации: из памяти извлечён закрытый ключ, из него выведен открытый X25519, и он совпал с аттестованным ключом живого анклава.
Что это значит по факту. Модель угроз здесь - недоверенный оператор сервера против приватности поиска контактов, а не перехват переписки: сквозное шифрование сообщений эти ошибки не затрагивают. Скомпрометированный ключ позволяет хосту выдавать себя за анклав и расшифровывать запросы CDSI - то есть видеть, какие телефонные номера сверяет пользователь. Отдельно: канал CDSI построен на постквантовой гибридной связке (Noise_NKhfs, X25519 + Kyber1024), но против этой атаки она не помогает - ключ вынимается прямо из памяти анклава, в обход всей криптографии.
Signal закрыла обе ошибки(тут и тут): один обработчик на шард теперь гарантируется внутри доверенной границы, а проверка и захват дескриптора клиента слиты в одну атомарную операцию.



