Введение
Эта история началась практически сразу после написания статьи об исследовании аркады небезызвестной корейской компании: в аркадном автомате Tank! Tank! Tank! от Namco вышел из строя жесткий диск (что неудивительно, т.к. производитель установил в автомат не отличающиеся надежностью Seagate 7200.12), диск взяли с рабочей аркады и скопировали его через WinHex, после чего игра перестала запускаться. Предположив, что целостность диска была нарушена неосторожным нажатием клавиши в окне редактирования данных на диске в WinHex, был взят другой диск с еще одного рабочего автомата, скопирован аналогичным образом, который также перестал запускаться. Тут-то и стало понятно, что в диск каким-то образом встроена защита от копирования.Namco System ES1
Аркада Tank! Tank! Tank!, выпущенная в 2009 году, работает на платформе System ES1, которая представляет из себя обычный компьютер тех лет на чипсете Intel Q35:- Материнская плата: Supermicro C2SBM-Q (Intel Q35 + ICH9DO)
- CPU: Intel Core2 Duo CPU E8400 @ 3.00GHz
- RAM: 2x512 MB DDR2 800 MHz 1.8V
- Видео: NVIDIA GeForce 9600 GT с 512 мегабайтами памяти типа GDDR3
- HDD: Seagate Barracuda 7200.12 160 ГБ (ST3160318AS) или Hitachi Deskstar 7K1000.C 160 ГБ (HDS721016CLA382)
- Операционная система: Arcade Linux (основана на Debian 4.0)
Все это укомплектовано к массивный корпус с прикрученным блоком питания на 110В.
Фотография System ES1, который поставляется с игрой Dead Heat. Установлен горизонтально, в отличие от варианта ES1 в Tank! Tank! Tank!.
На платформе ES1 всего было выпущено 9 игр, 4 из которых рассчитаны исключительно на внутрияпонский рынок. Последняя игра была выпущена в 2014 году, так что можно полагать, что новых игр на данной платформе не появится. На территории России и Украины мне встречались всего 4 ES1-игры: Tank! Tank! Tank!, Dead Heat, Dead Heat Riders и Nirin.
Доверенная загрузка и TPM
Особенность данной платформы в том, что она использует так называемую доверенную загрузку (Trusted Boot) со статичным корнем доверия (Static Root of Trust) с помощью крипточипа Trusted Platform Module (TPM) версии 1.2, встроенного в материнскую плату. TPM — замечательная штука — что-то вроде смарт-карты, которая несет в себе RSA-ключ, зашитый производителем на этапе производства, с возможностью генерирования своих ключей, приватная часть которых никогда не покинет TPM, загрузки уже существующих ключей, с небольшим энергонезависимым хранилищем произвольных данных (NVRAM) на борту, генератором случайных чисел и еще кучей всего. Но самое интересное, что предоставляет TPM — конфигурационные регистры платформы (Platform Configuration Registers, PCR), которые можно расширить SHA-1-суммой каких-то произвольных данных. Очень важно отметить, что эти регистры нельзя ни сбросить, ни установить в нужное значение, а только дополнить новой SHA-1-суммой, от которой сам TPM возьмет новую SHA-1-сумму от конкатенации старого и нового значения. Проще говоря, TPM выполняет следующую команду, если вы отправляете в PCR NEW_HASH:PCR[i] = SHA1(PCR[i] + NEW_HASH)
BIOS/UEFI материнской платы, если он поддерживает спецификации Trusted Computing Group (TCG), измеряет (т.е. отправляет в TPM хеши) всего, что участвует в загрузке с момента включения компьютера: BIOS/UEFI Boot Block, сам BIOS/UEFI, сервисы UEFI, SMBIOS, таблицы ACPI, Option ROM устройств (например, сетевых карт), MBR или загрузчик EFI, разделы диска, и еще кучу всего.(из Evil Maid Just Got Angrier)
BIOS/UEFI не могут осуществлять измерения чего-либо, что делается после загрузки MBR или UEFI-загрузчика, поэтому, в случае Linux, загружаемое ядро и initrd остаются неучтенными в PCR. Чтобы производить измерения после MBR, существуют загрузчики, поддерживающие TPM и осуществляющие доверенную загрузку со статичным корнем доверия: TrustedGRUB, TrustedGRUB2, GRUB-IMA. Последний используется в System ES1. Эти загрузчики отправляют в TPM хеши самих себя (stage1 и stage2 в случае GRUB), свои настройки и загружаемые модули (ядро, командную строку ядра и initrd, в случае Linux).
TPM может зашифровать произвольные данные RSA-ключом с привязкой к значениям PCR, и расшифровать их можно будет только в том случае, если значения PCR совпадут. Если мы зашифруем таким образом данные, то, в случае модификации BIOS/UEFI, загрузчика, модулей GRUB, ядра, initrd или всего лишь командной строки ядра, данные не расшифруются из-за несовпадения регистров.
Из популярного софта TPM используется, насколько мне известно, только в Microsoft BitLocker. TPM можно использовать в качестве хранилища сертификатов для всяких банк-клиентов, VPN и SSH-доступа, и очень обидно, что его использует так мало людей, единицы, учитывая его стоимость (≈$10, дешевле, чем типичные смарт-карты), возможности и тот факт, что он уже установлен во многие модели ноутбуков, а в последних процессорах от Intel вообще реализован на уровне ПО и доступен всем.
Защита ES1
В Namco System ES1 есть три степени защиты от копирования.Первая — принцип доверенной загрузки: файлы и ресурсы игры зашифрованы с помощью ключа в TPM и привязаны к значениям PCR. Производитель, перед отправкой автомата покупателю, запускает процесс зашифровки данных на автомате, и после этого диск с игрой будет запускаться только на той аркаде, где ее запустили первоначально. Для шифрования используется AES-256 в CBC-режиме средствами крайне простого и ныне усопшего loop-AES — модуля ядра для шифрования произвольных данных на блочных устройствах. Также имеется шифрованный LUKS-раздел на диске, в котором хранится копия данных игры вместе с обновлениями, сохранениями и другими данными.
Вторая степень защиты — защита HDD.
Почему же игра не запускается после копирования диска? Быть может, производитель написал свою прошивку для контроллера диска, которая стирает данные при обращении к какому-то сектору, которое происходит при посекторном копировании диска, но никогда не происходит при обычном использовании диска игрой и ОС? Зная Namco, они могли пойти на такой шаг, ведь у них есть средства, специалисты и время на создание аппаратов, основанных на PlayStation 2 (System 246) и 3 (System 357).
Но нет, все просто и по-злому гениально: в MBR диска в поле Disk Signature указаны нули. Как только вы подключаете этот диск к компьютеру под управлением ОС Windows, она обнаруживает нули, ей это не нравится, ведь Windows использует Disk Signature в качестве уникального идентификатора диска, генерирует случайный и по-тихому записывает его на диск. Материнская плата аппарата, во время загрузки игры, считывает MBR и отправляет его хеш в TPM. Когда дело доходит до расшифровки данных, TPM PCR не совпадают, данные не могут расшифроваться и игра не запускается. Сделано это было явно намеренно — все утилиты для управления разделами в Linux генерируют случайный Disk Signature, а не нули.
$ cmp -l mbr_working mbr_broken | gawk '{printf "%08X %02X %02X\n", $1-1, strtonum(0$2), strtonum(0$3)}'
000001B8 00 4B
000001B9 00 4D
000001BA 00 17
000001BB 00 CC
Помимо TPM, который используется только для расшифровки данных средствами ОС, в самих играх используется USB-донгл HASP HL Max. Точнее сказать, не используется, а только проверяется его наличие, и эта проверка обходится буквально одним патчем, либо вообще отключается в конфигурационном файле. Глупо, расточительно и вообще непонятно, зачем он нужен.
Из примечательного: пароль на BIOS и GRUB, который можно получить перебором — 016ystn или arcade, в зависимости от игры.
Варианты атаки
Итак, у нас имеется:- Образ диска, который больше не запускается
- 2 работоспособных автомата
- 2 неработоспособных автомата
Наша задача — восстановить неработоспособные машины, диски которых вышли из строя. Для этого нам нужно заполучить зашифрованные данные игры в незашифрованном виде с работоспособных аппаратов, для чего необходимо каким-то образом сначала получить ключ шифрования.
Эксплоит через USB-устройство
Второй вариант — драйвер звукового и MIDI-устройства Caiaq, который мне, к сожалению, также не получилось проэксплуатировать.
Атака Cold boot
DMA-атака
Расшифровка данных
Получить данные памяти еще полдела, нужно найти в них ключ AES и расшифровать файл игры. Для первой задачи умные люди из Принстонского университета написали утилиту aeskeyfind, которая побайтно проходит по всему образу, принимая случайные данные в оперативной памяти за AES-ключ, и пробует найти недалеко от него временные ключи, получаемые из основного и используемые в AES-раундах (так называемое расписание ключей, key schedule). Если мы нашли что-то похожее в памяти — отлично, у нас появился кандидат на правильный ключ шифрования!$ aeskeyfind memdump_0x0-0x100000000_20160524-172534.bin
f322ee68145f5f32dea7252b2de00ff30003bb2775b7164f7211ba56fbe2012a
7523dfd705d26ce4f34ee872ec88f7ede80ac8ea0f104d3aba4a5d38bfa5849f
103687fef032a17e830b6709c29bd805
Нашлось два 256-битных ключа и один 128-битныйДля расшифровки файлов, зашифрованных loop-AES, я написал простейший скрипт на Python, т.к. существующие утилиты не умеют работать с тем ключом, который мы нашли в оперативной памяти (мастер-ключ), а принимают на вход «пароль», из которого с помощью функции формирования ключа получается мастер-ключ. «Пароля» у нас нет, и оказалось проще написать свое, чем модифицировать чужое.
Скрытый текст
#!/usr/bin/env python3
import sys
import struct
from Crypto.Cipher import AES
if len(sys.argv) < 3:
print("Namco encrypted game file (.apps, LOOP-AES) decryptor.")
print(sys.argv[0], "USAGE: ENCRYPTED_FILE KEY_FILE OUTPUT_FILE")
print("KEY_FILE should be in binary format.")
print("Use echo KEY_HERE | xxd -r -p")
sys.exit(1)
aesfile = open(sys.argv[1], 'rb')
key = open(sys.argv[2], 'rb').read()
output = open(sys.argv[3], 'wb')
iv = 0
while True:
enc_data = aesfile.read(512)
if not enc_data:
break
cipher = AES.new(key=key, mode=AES.MODE_CBC, IV=struct.pack('LL', iv, 0))
output.write(cipher.decrypt(enc_data))
iv += 1
$ echo f322ee68145f5f32dea7252b2de00ff30003bb2775b7164f7211ba56fbe2012a | xxd -r -p > key
$ ./decrypt.py v352us.apps key v352us.app
$ file v352us.app
v352us.app: Squashfs filesystem, little endian, version 3.1, 655177264 bytes, 6062 inodes, blocksize: 131072 bytes, created: Sat Nov 28 06:26:17 2009
Первый же ключ подошел, отлично!У нас есть все, чтобы сделать диск таким, какой он был до первого включения аппарата на заводе, а это значит, что мы можем восстановить любой автомат Namco System ES1 так же, как это сделал бы производитель!
С первого раздела, из директории arcade, удаляем зашифрованный файл *.apps и ключ шифрования
sealkey
, копируем файл с расшифованными данными *.app и создаем пустой файл RECOVERY
, чтобы скрипты перешифровали его при запуске. Должно получиться что-то подобное:p1/arcade % ls -lah
total 626M
drwxr-xr-x 2 root root 4.0K Jun 27 19:02 .
drwxr-xr-x 7 root root 4.0K Nov 28 2009 ..
-rw-r--r-- 1 root root 396 Nov 28 2009 config
-rw-r--r-- 1 root root 75 Nov 28 2009 partab
-rw-r--r-- 1 root root 0 Jun 27 19:02 RECOVERY
-rw-r--r-- 1 root root 625M Nov 28 2009 v352us.app
Обратите внимание на второй раздел, это раздел с обновлениями игры. Если на нем есть файл *.pkg, то необходимо удалить файл
INITIALIZED
, чтобы игра обновила сама себя, иначе вы получите устаревшую версию.Подключаем диск в System ES1, включаем автомат и наблюдаем, как игра сама себя зашифровывает и копирует файлы на LUKS-раздел! Ура!
Реальная история:
Была очень печальная история, году в 2010 примерно, когда Nirin высыпался, и с другого аппарата техник снял, чтобы сделать копию на Винде с помощью Акрониса. Копию делает, сообщает, что все ОК. Но диск, с которого пытались сделать копию, потом, при подключении назад, показывает синий экран смерти и табличку, что у вас проблемы с диском. Упрямый парень на этом не остановился и полез в третий аппарат. История повторилась. Но ничего не страшит нашего человека — он позвонил своему коллеге в другой город и попросил ему почтой отправить диск с Нирина. Уехали все 4 системника в Лондон (Европейское представительство Намко), и все за счет парня, который думал, что упрямство победит! Почти 8000 евро за все обошлось (ремонт и туда-обратно логистика).Что делать, если вы настолько же упрямый, и у вас не осталось работоспособных аппаратов? Не беда! Достаточно вернуть нули в поле идентификатора диска в MBR, т.е. записать 4 байта нулей по смещению 0x1B8. В Linux это делается одной командой:
# sudo dd if=/dev/zero of=/dev/sdX bs=1 count=4 seek=440
А в Windows можете использовать, например, WinHex.После этого игра должна запуститься, и можно проделать все вышеописанные манипуляции, чтобы заполучить расшифрованные файлы и восстановить остальные аппараты.
25.06.2018 UPD: По всей видимости, Nirin был первой игрой на System ES1, и Namco не знали, как корректно реализовывать защиту с использованием TPM. Игра не использует шифрование средствами TPM, а получает ключ путем хеширования состояния значений Trusted Boot PCR.
Получить ключ шифрования можно без DMA-атаки, путем модификации файла
filesystem.squashfs
для сохранения состояния /sys/kernel/security/tpm0/binary_bios_measurements
и /sys/class/tpm/tpm0/pcrs
и реконструкции оригинальных значений TPM PCR.Скрипт для реконструкции значений PCR: github.com/ValdikSS/binary_bios_measurements_parser
Заключение
Архитектура и качество скриптов и утилит Arcade Linux оставили очень положительное впечатление о программистах Namco, а трюк с Disk Signature в MBR так вообще высший пилотаж. Конечно, для большей защиты следовало включить IOMMU, чтобы DMA-атаки были (почти) невозможны, а ключи шифрования хранить в debug-регистрах процессора, а не в оперативной памяти, но, все же считаю защиту Namco System ES1, как минимум, интересной, ее было нескучно исследовать и взламывать.Образы и расшифрованные файлы игры доступны для скачивания на трекере-со-свиньями.
Помогу чем смогу, если вам нужно восстановить ПО аркад, а если вы разработчик аркадных игр под Linux (но не ссаных азартных/гемблинг-автоматов!), буду рад сделать вам надежную защиту, которую смогут взломать только очень смышленые люди.
Скрытый текст