О недавней уязвимости в банкоматах Diebold Nixdorf

image-loader.svg

Дисклеймер: данная статья публикуется исключительно для ознакомления и ни в коем случае не является руководством к действию. Описанные в материале уязвимости были обнаружены автором статьи в рамках проекта, согласованного с производителем банкоматов. На данный момент они исправлены компанией Diebold Nixdorf, которая была уведомлена Positive Technologies в соответствии с принципами ответственного разглашения (responsible disclosure). В качестве дополнительного фактора защиты вендору рекомендовалось включить физическую аутентификацию для оператора во время установки встроенного ПО. Это позволяет убедиться, что изменения в банкомат вносит сотрудник, а не злоумышленники.

Приветствую! На днях Positive Technologies опубликовала новость о том, что банкоматы производителя Diebold Nixdorf (ранее Wincor), а точнее модели диспенсеров RM3 и CMDv5, содержат уязвимость, благодаря которой можно производить выдачу наличных и заливать модифицированную (уязвимую) прошивку. И поскольку я и мой бывший коллега Алексей Стенников имеем непосредственное отношение к нахождению этой уязвимости, я хотел бы поделиться некоторыми ее деталями.

29 октября я выступлю на конференции Hardwear.io, посвященной безопасности аппаратных решений, где расскажу о найденной уязвимости в деталях.

Введение

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

image-loader.svg

Верхняя часть — это обычный ПК, который чаще всего лежит в этой части плашмя. В него воткнуто огромное количество USB-устройств: камеры, принтеры, картридеры и… тот самый диспенсер, который находится в нижней части. Именно этот ПК из верхней части (которая, кстати, считается небезопасной) и является основной целью для малварщиков. Но мы не такие, ВПО — это плохо! Поэтому спускаемся по USB-кабелю в нижнюю часть банкомата, где нас ждёт…

Safe zone (она же сейф, диспенсер) — безопасная и заведомо защищённая часть банкомата. Закрывается она на ключ, который есть только у сервисных инженеров и инкассаторов, сделана не из пластика (в отличие от верхней части) и часто укреплена бетоном либо вмонтирована в стену. Именно в сейфе находится то, ради чего и взламываются банкоматы, — банкноты. Они разложены по кассетам с нужными номиналами, каждая из которых также закрыта на ключ. Из кассет деньги достаются присосками, едут по конвейеру к »шторке» (shutter), после чего извлекаются пользователем.

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

Зачем взламывают диспенсер вместо ПК и при чём тут blackbox?  

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

Кроме того, на диспенсеры в своё время часто совершались атаки типа blackbox, при которой, единожды захватив USB/COM-трафик выдачи наличных на одном устройстве, неизвестный мог подойти с ним же к другому, повторить и получить деньги. Сейчас же такое провернуть кому-либо вряд ли удастся, потому что повсеместно применяются анти-blackbox техники: например, сессионные rolling-ключи для шифрования USB-трафика и использование криптографии практически на каждом этапе. Теперь лишь компьютер банкомата может работать с этим шифрованием, поэтому вклиниваться в трафик злоумышленник чаще всего уже не может.

Но тогда и не было бы данной статьи, как и упомянутой новости. В нашем проекте была одна небольшая брешь (к счастью, её уже нет). И о ней ниже.

В чём уязвимость, брат?

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

Прежде всего стоит сказать, что прошивки зашифрованы ключами, которые известны только разработчику. Описанные Positive Technologies уязвимости (по одной на устройство) заключаются в том, что злоумышленник может загрузить на диспенсер прошивку, не зная этих самых ключей шифрования (они появятся дальше в статье в виде KEY0 и KEY1). То есть, имея чистый код, он может его модифицировать как хочется, зашифровать обратно и загрузить в банкомат, после чего произвести выдачу в обход имеющихся алгоритмов шифрования USB-трафика. Ну, а теперь к деталям…

image-loader.svg

Конец 2017-го, начало проекта

В рамках проекта в одном банке мне и Алексею достались два файлика: у одного было расширение BTR (bootloader), у второго — FRM (firmware). У файлов имелись понятные заголовки, но при этом совершенно непонятное содержимое. Мы и так, и этак пытались подойти к расшифровке содержимого (становилось очевидно, что оно зашифровано), но безуспешно. На этом проект мог бы и закончиться, и файлы действительно пролежали несколько месяцев на жестком диске, пока мудрый Алексей не решил поискать плату диспенсера на eBay. Плата там, как вы уже могли догадаться, нашлась, и спустя какое-то время оказалась у Алексея на столе.

image-loader.svg

Без контроллера плохо, с контроллером — хорошо

После некоторых манипуляций с прозвонкой был успешно найден разъём JTAG, который находился прямо рядом с главным процессором. Кроме главного, на плате имелись ещё два процессора, назначение которых нам было не очень понятно: CollectorBooter и DispenseBooter. Тем не менее память всех трёх процессоров была сдамплена для дальнейшего анализа.

Ну, сдампили и сдампили, чо бубнить-то, но что дальше? Мы решили, что подходить стоит со стороны заливаемой прошивки, зашифрованные файлы которой у нас, напоминаю, были. А дампы хоть и имелись, всё же приятнее работать с прошивкой в чистом виде.

ПО от вендора

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

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

image-loader.svg

Шифрование файлов прошивки

Алгоритм шифрования представлял из себя обычный XTEA, но с необычной для него дельтой: 0xF27716BA. Как она была сгенерирована, безопасна ли — мы не знаем. Но можно точно сказать одно: она не гуглится.

В качестве ключа шифрования XTEA использовались следующие входные данные:

  • пять первых двордов, идущих сразу же после имени прошивки, указанного в заголовке. Мы назвали их Header-Dwords

  • внешний ключ KEY0 длиной 8 байт, который пока неизвестно откуда брался

  • внешний ключ KEY1 длиной 16 байт, который мы также не знали, где брать

Спустя время мы всё же нашли участок кода, вычитывающий и KEY0, и KEY1. Оказалось, что находятся они в специальной области по смещению 0x64000000, смещение в которой по умолчанию было жёстко задано. Далее мы сделали дамп данной области и извлекли оттуда оба внешних ключа. Применив эти ключи в заранее написанном на коленке расшифровщике, мы получили… Нет, не прошивку.

AP32-архивы

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

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

Самоподписывание

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

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

Так мы и сделали. Вместо оригинальных 2048 (кажется) был успешно вставлен ключ на 512 бит.

image-loader.svg

Заливаем модифицированную прошивку

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

image-loader.svg

А так список выглядит, когда устройство обновляется:

image-loader.svg

Вот этот последний девайс и принимает файлики. А работает он по протоколу DFU (Device Firmware Update), о чём можно было догадаться, даже не имея самой платы на руках. Дело в том, что в конце каждого файла прошивки есть определённая структура, которая содержит тег »UFD».

Сначала устройству отправляется команда DFU_DETACH протокола, после чего выполняется команда USB — UsbCyclePort, которая делает доступным интерфейс, принимающий прошивку. Кто работал с данным протоколом, скажет, что в нём ещё есть команда DFU_UPLOAD (в данном случае выгрузка), но в нашем случае она не была реализована.

Запуск прошивки

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

Выдача?

Пока нет. Прежде чем произвести выдачу, требовалось разобраться с тем, как же всё-таки отправлять диспенсеру команды. Покопавшись в Java-коде, нам удалось найти специальные JAR-файлы, отвечающие за self-test, то есть за тестирование компонентов диспенсера. Из этого кода удалось выяснить следующее:

  1. Во взаимодействии компьютера банкомата и диспенсера участвует смарт-карта (она давно уже виднелась на плате)

  2. Используется TPM (Trusted Platform Module)

  3. Используется Keystorage, в котором хранятся счётчики сессий (об этом ниже), сертификаты и базовый ключ (Basekey)

  4. Есть четыре направления, для каждого из которых используется свой сессионный ключ и счётчик: PC → Firmware IN/OUT, Firmware → PC IN/OUT

Смарт-карта

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

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

image-loader.svg

Сессионные ключи (нет, спасибо)

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

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

Осталось сделать то же самое в Java-софте, чтобы не заморачиваться с написанием кода с нуля. К слову, здесь же по коду стало понятно, что используется алгоритм шифрования Aes-EAX.

Выдача!

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

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

Лишь после этого в диспенсер отправилась команда с номерами кассет и количеством банкнот для извлечения. Банкомат начал радостно жужжать, предвкушая, как делится наличностью с товарищами исследователями, но денег мы так и не увидели. Мы просто не знали забыли, что нужно ещё открыть шторку. Дубль два — и свежие »фантики» (специальные вендорские купюры) были у нас в руках. Ура!

Выводы

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

На этом, пожалуй, всё. Отдельно я хотел бы отметить работу Алексея над »железячной» частью проекта и приобретённую им плату диспенсера, которая по-прежнему лежит у меня на столе.

© Habrahabr.ru