Вы прикладываете ключ-карту к считывателю, и дверь офиса открывается. Но что, если такой пропуск может взломать и скопировать любой желающий?
В 2020 году Shanghai Fudan Microelectronics выпустила новые смарт-карты FM11RF08S. Производитель заявил об их полной защищенности от всех известных методов взлома. Группа исследователей проверила эти заявления и обнаружила встроенный бэкдор, позволяющий получить полный доступ к данным карты.
В этой статье я расскажу захватывающую историю о том, как нашли этот бэкдор, и разберу катастрофические последствия его внедрения. Этот случай наглядно демонстрирует опасность слепого доверия маркетинговым заявлениям о безопасности и важность независимого аудита критических систем.
Стандартик, который выжил: феномен долговечности MIFARE Classic
MIFARE Classic — это динозавр мира бесконтактных карт, который почему-то до сих пор не вымер. Каждый день миллионы людей по всему миру прикладывают эти карты к считывателям: открывают двери офисов, оплачивают проезд в метро и получают скидки на любимый кофе.
Увы, этот стандарт оказался очень ненадежным. MIFARE Classic взламывали так часто, что это стало народным спортом среди хакеров. Помните нашу статью про взлом проездных билетов бостонского метро? Это только верхушка айсберга.
А производители? Они пошли по пути наименьшего сопротивления. Вместо того чтобы полностью переработать уязвимую архитектуру, они выпускают «заплатки», словно пытаются залатать дыры в тонущем корабле. Все ради обратной совместимости со старым оборудованием, которое установлено по всему миру.
И вот в 2020 году крупная китайская компания Shanghai Fudan Microelectronics представила очередную смарт-карту на базе MIFARE. Производитель назвал ее неуязвимой для существующих методов взлома. Маркетинговые материалы пестрели громкими фразами: «улучшенная защита», «устранение слабых мест в алгоритме», «функции безопасности нового поколения». При этом в технической документации FM11RF08S упоминались лишь «улучшения криптографического протокола» — без единой конкретной детали.
Хакерское сообщество сначала отреагировало традиционным «challenge accepted» и приготовилось к быстрой победе. Но что-то пошло не так. Прошло несколько лет, а новые карты оставались неприступными.
Похоже, разработчики действительно проделали серьезную работу над ошибками.
И тут на сцену вышла команда исследователей под руководством Филиппа Тевена. Они решили принять этот вызов, не подозревая, какие удивительные открытия ждут впереди.
Алгоритм работы карты
Чтобы по достоинству оценить открытия Тевена и его команды, сперва нужно проговорить первые этапы работы протокола CRYPTO-1, который отвечает за аутентификацию карт MIFARE Classic.
-
Пользователь подносит карту к считывателю.
-
Считыватель отправляет карте команду авторизации, указывая два параметра: целевой блок памяти и ключ, с которым он будет работать. Допустим, это KeyA.
Память карты разделена на блоки (сектора) — 16 или 40 в зависимости от модели. Каждый блок защищен парой ключей с разными правами доступа. KeyA обычно позволяет считывать информацию, например идентификатор владельца, а KeyB дает возможность изменять данные в блоке.
-
Карта отвечает на запрос считывателя, генерируя четырехбайтное псевдослучайное число — Nonce (number used once).
-
Считыватель комбинирует Nonce с заранее известным ключом. В нашем случае это KeyA. Эта комбинация проходит через шифр CRYPTO-1. Получившееся зашифрованное значение отправляется обратно на карту.
-
Карта одновременно выполняет те же вычисления, используя свою копию ключа и сгенерированный Nonce. Если результат вычислений карты совпадает с ответом считывателя, аутентификация проходит успешно. После этого система генерирует поток ключей для последующего шифрования данных.
Вся дальнейшая коммуникация происходит в зашифрованном виде. Для доступа к новому блоку карты запускается процесс вложенной аутентификации: считыватель шифрует соответствующую команду, а карта шифрует новый Nonce уже ключом из нового блока. Запомните этот момент — он станет ключевым в нашей истории.
Первые находки: особенности реализации CRYPTO-1 в FM11RF08S
Исследовательская группа под руководством Тевена начала изучать различия между реализациями алгоритма CRYPTO-1 в новой версии карты и оригинальном MIFARE Classic.
В новой карте при вложенной аутентификации использовались статические значения Nonce — то есть числа, которые должны быть случайными, оказались неизменными. Для сравнения: в оригинальных картах MIFARE Classic значение Nonce формировалось динамически с помощью регистра сдвига с линейной обратной связью (Linear Feedback Shift Register, LFSR).
Опытные хакеры знали: если достаточно долго держать карту у считывателя и пытаться авторизоваться снова и снова, генерируемые значения становятся предсказуемыми.
Эта особенность значений Nonce в MIFARE Classic делает возможным проведение так называемых Nested-атак.
Разработчики FM11RF08S пошли другим путем. При первом знакомстве карты со считывателем все шло по классическому сценарию. А вот дальше начиналось самое интересное: при вложенной аутентификации карта выдавала один и тот же Nonce для каждого блока памяти. Дополнительные исследования показали, что это значение зависит от трех параметров: номера сектора, UID карты и значения ключа доступа. Таким образом, каждая карта FM11RF08S содержала индивидуальный набор постоянных Nonce, привязанных к определенной комбинации ключей и секторов.
На первый взгляд, идея казалась неплохой. Классическая Nested-атака действительно не работала — ведь теперь злоумышленник не мог предсказать следующее значение Nonce, сколько бы времени ни потратил на наблюдение за картой. Но, как часто бывает в мире безопасности, закрыв одну дверь, разработчики случайно оставили открытым окно…
При использовании одного ключа доступа для аутентификации в двух разных блоках при вложенной аутентификации карта выдает разные Nonce, но шифрует их одним и тем же ключом. Злоумышленник может собрать несколько пар таких зашифрованных значений и восстановить исходный ключ без полного перебора. Исследователи назвали этот метод взлома атакой повторного использования ключей (Reused Keys Nested Attack).
Представьте, что есть неизвестный ключ KeyX, который используется в нескольких блоках карты. Для его подбора достаточно иметь доступ всего к одному «легальному» ключу в любом другом секторе карты:
-
Выполняешь первую аутентификацию, используя известный ключ, и таким образом устанавливаешь шифрованное соединение с картой.
-
Проводишь вложенную аутентификацию в тех блоках, где предположительно используется KeyX, и сохраняешь каждый зашифрованный Nonce, который выдаст карта.
-
Перебираешь все возможные значения ключа. Для каждого собранного Nonce получатся сотни ключей, которые теоретически могли его зашифровать.
-
Сравниваешь полученные наборы потенциальных ключей для Nonce разных секторов. Нужно найти тот ключ, который присутствует в каждом наборе: вуаля, это и есть искомый KeyX.
Преимущество этой атаки — в скорости: компьютер перебирает ключи «офлайн» без обращения к карте. Однако для успешной атаки требуется соблюдение двух важных условий. Во-первых, нужно иметь хотя бы один рабочий ключ доступа — своего рода пропуск в систему. Во-вторых, где-то в карте должны использоваться одинаковые ключи для разных секторов.
Даже соблюдение этих условий не гарантирует успешный взлом: получится узнать только повторяющиеся ключи — остальные останутся в безопасности. Казалось бы, не самый практичный метод взлома, но это еще не все, что нашла команда Филиппа Тевена.
Подозрительный ключ
Исследователи применили фаззинг — они отправляли на карту нестандартные команды и искаженные последовательности байтов, наблюдая за реакцией карты.
По идее карта должна быть довольно избирательной в общении. На этапе аутентификации она должна реагировать только на три команды: аутентификацию с ключом keyA (код 60**), аутентификацию с ключом keyB (код 61**) и команду остановки HLTA (код 5000). Но команда Филиппа Тевена обнаружила отклонение от протокола: карта отправляла Nonce в ответ на любую команду серии 6*00, от кода 6000 до 6f00 вне зависимости от блока.
Заинтригованные этим поведением, исследователи решили копнуть глубже. Они взяли карту с известными ключами, настроили разные ключи keyA и keyB и начали методично проверять все варианты команд 6*00. Выяснилось, что команды можно разделить на 4 группы по поведению карты:
-
Группа 1: 6000, 6200, 6800, 6a00 → дает Nonce 4e506c9c (аутентификация успешна);
-
Группа 2: 6100, 6300, 6900, 6b00 → дает Nonce 7bfc7a5b (аутентификация успешна);
-
Группа 3: 6400, 6600, 6c00, 6e00 → дает Nonce 65aaa443 (аутентификация не удалась);
-
Группа 4: 6500, 6700, 6d00, 6f00 → дает Nonce 55062952 (аутентификация не удалась).
Когда они изменили keyA — изменились Nonce для групп 1 и 3. Сделали keyA и keyB одинаковыми — получили два разных Nonce вместо четырех: один Nonce для групп 1 и 2 с успешной аутентификацией и другой для групп 3 и 4. Похоже, что для последних двух групп команд карта ожидала получить некий другой ключ — keyC…
Подбор ключа
И тут в головах исследователей щелкнуло: «А что если этот загадочный keyC используется во всех блоках карты?» И если так, то... Бинго! К нему можно применить уже знакомую нам атаку повторного использования ключей. Алгоритм прост:
-
Провести первичную аутентификацию при помощи keyA.
-
Сделать несколько вложенных аутентификаций при помощи аномальных команд в других разделах памяти и сохранить полученные Nonce.
-
Вычислить все возможные значения ключа для каждого собранного Nonce.
-
Сравнить полученные наборы значений и выделить ключ, который встречается в каждом из них.
Python-скрипт справился с задачей менее чем за две минуты и успешно вычислил искомый ключ:
KeyC оказался не просто ключом — он был универсальной отмычкой и позволял аутентифицироваться независимо от значений keyA и keyB. С его помощью злоумышленник мог читать любые пользовательские блоки данных, даже если права доступа запрещают их чтение обычными ключами.
Но холодный пот прошиб исследователей, только когда они проверили этот ключ на других картах FM11RF08S. Ключ работал на всех картах независимо от партии и даты выпуска.
Это был не баг. Не ошибка. Не случайность. Это был самый настоящий бэкдор — недокументированный механизм, дающий привилегированный доступ к карте в обход стандартных средств защиты. Сам факт существования такого ключа — серьезнейший удар по защите FM11RF08S и по всем системам безопасности, которые полагаются на эти карты, но это было только начало.
Как доломать бэкдор
Обнаруженный бэкдор давал доступ к служебным разделам памяти, где хранятся ключи keyA и keyB, однако значения ключей оказались маскированы. Для большинства хакеров это стало бы сигналом остановиться — цель достигнута, бэкдор найден, можно писать отчет. Но команда Тевена пошла дальше.
Они поставили перед собой новую цель: найти способ подбора этих ключей. Успех означал бы возможность беспрепятственно клонировать и эмулировать любую карту FM11RF08S.
Они выработали следующий алгоритм:
-
Аутентифицировались в блоке при помощи мастер-ключа keyC.
-
Карта отправляла Nonce в открытом виде, который исследователи сохраняли.
-
Считыватель шифровал Nonce ключом бэкдора и отдавал карте. Карта валидировала значение и устанавливала шифрованный канал связи.
-
Теперь исследователи инициировали вложенную аутентификацию в том же секторе с keyA.
-
Карта отправляла тот же статический Nonce, но уже зашифрованный ключом keyA.
Последний акт этой драмы оказался чисто математическим. Исследователи использовали операцию XOR между открытым и зашифрованным Nonce для вычисления ключевого потока. Затем, применив модифицированную версию static nested attack, они научились восстанавливать значение keyA. Процесс требовал перебора нескольких десятков тысяч вариантов, но на современном компьютере занимал всего 3-4 минуты.
А дальше началась настоящая оптимизация. Используя разные статистические трюки, команда довела процесс до совершенства:
-
32 случайных ключа? 17 минут, пожалуйста.
-
16 ключей, где keyA = keyB? Полчаса максимум.
-
А если повезет найти карту с 24 ключами, из которых 8 повторяются? 40 секунд, и дело в шляпе!
Итоговый вердикт был подобен приговору: встроенный производителем бэкдор не просто пробил брешь в защите — он превратил ее в карточный домик. Представьте банковское хранилище, где у каждой ячейки свой уникальный код, а где-то в стене есть потайная кнопка, открывающая все ячейки разом. Именно это и сделал производитель с FM11RF08S. Зная мастер-ключ, злоумышленник мог целиком скопировать любую карту.
Неутешительные выводы
Пожалуй, история с FM11RF08S войдет в учебники как классический пример того, как не надо делать системы безопасности. Обнаруженный бэкдор превратил «самую защищенную реализацию MIFARE Classic» в решето, поставив под угрозу миллионы устройств по всему миру. В том числе и на важных объектах: в аэропортах, на электростанциях и промышленных предприятиях.
Как устранить риск? Увы, решение только одно, и оно похоже на удаление больного зуба — полный отказ от использования скомпрометированных карт. А их количество... что ж, давайте просто скажем, что счет идет на миллионы.
Вскоре после первого взлома FM11RF08S идентичный бэкдор с тем же мастер-ключом обнаружился в более старых картах Shanghai Fudan Microelectronics (FM11RF08 и FM11RF32), а также в продукции других производителей — NXP Semiconductors до 2009 года выпуска и Infineon до 2013 года.
Это наводит на мысль о том, что бэкдор сознательно внедрен на производстве много лет назад. Может, для упрощения отладки? Или были какие-то договоренности с госструктурами? Или... мы можем только гадать. Но факт остается фактом: системы безопасности по всему миру годами использовали карты со встроенной уязвимостью.
Эта история преподносит три важных урока. Первый: репутация не гарантирует безопасность. Второй: принцип «безопасность через неясность» в криптографии несостоятелен. Засекречивание алгоритмов создает лишь иллюзию защиты — единственное надежное решение заключается в использовании открытых алгоритмов, проверенных экспертным сообществом. Третий: доверяй, но проверяй. Независимый аудит и тестирование на проникновение — это не лишние траты, а жизненная необходимость.
P.S. Статья основана на оригинальном исследовании Филиппа Тевена MIFARE Classic: exposing the static encrypted Nonce variant и ряде открытых публикаций.
Автор: breakmirrors