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

▍ Первый взгляд


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

После загрузки и бесцельного кликанья по различным опциям UI я просканировал порт, но ничего интересного не нашёл. Что ж, будем разбирать.



На вид корпус и печатные платы выполнены добротно. Всего устройство включает несколько плат: небольшую интерфейсную плату для внешних разъёмов, основную плату и вертикальную, на которой расположено гнездо для карт. Похоже, что основная SoC представляет кастомную ASIC, которая содержит двухъядерный процессор Arm под кодовым именем «Samoa II». Но я забегаю вперёд… Согласно документации Wordline, это действительно кастомная ASIC, а не просто серийный чип с другой маркировкой. Рядом с ней находится небольшая микросхема флэш-памяти и RAM.

▍ Защита от проникновения


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

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


Изогнутый рисунок дорожек на плате дисплея, позволяющий обнаруживать вскрытие

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


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

Собрав терминал обратно, я понял, что моё вмешательство не прошло незамеченным. Теперь дисплей устройства показывал лишь красный экран с надписью «OUT OF ORDER. TAMPERED STATE». В этом режиме терминал абсолютно невосприимчив к какому-либо внешнему вводу. Значит, всё?



▍ Снятие микросхемы и чтение прошивки


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

Флэш-память в BGA-корпусе, выпаянная с платы и подключённая к устройству чтения

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

Обратившись за подсказкой к своим друзьям, я смог-таки разобраться в этой схеме. Дело в том, что вместо использования стандартной схемы — 2048 байт полезная нагрузка + 64 байта ECC/резервной области — здесь используется 3 блока данных по 694 байта, каждый из которых сопровождается 10 байтами ECC. Причём байты ECC используются не полностью. Вместо этого последние 16 байт резервной области, похоже, выступают в качестве метаданных для файловой системы YAFFS2.

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

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

yomani-unpacker на Github

Теперь стало ясно, на какой ОС работает этот девайс. Я обнаружил файловую систему Linux со множеством интересных файлов. В основе системы лежит ядро 3.6, собранное с помощью Buildroot 2010.02 (!) в феврале 2023 года. Похоже, что в ней используется кастомный загрузчик, «Booter v1.7». И хотя я не знаю, насколько свежей является считанная мной прошивка, вышла она явно после февраля 2023. Честно сказать, встреча столь престарелого ядра вызывает беспокойство. В рамках пространства пользователя здесь используются элегантные скрипты инициализации, busybox и uClibc (последний релиз 13 лет назад). А также libcrypt версии 0.9.26 — ай-ай.

▍ Случайное получение root-доступа


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

Флэш-память снова подключена к плате — почти как новая

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

Прощупывание отладочного разъёма

Почти сразу же я нащупал некую активность на одной из линий отладочного разъёма. Бинго!

------------------------------------------------------------------------
Booter: 1.7b+00002:gbe6b338 Jun  3 2014 08:51:58 owi
Reset reason: Tamper
Start USB boot ...
Got address 0x00000015
Enumerated.
Dfu timeout
yaffs: checkpoint restore ... KO!
yaffs: clean up the mess caused by an aborted checkpoint
file "hwinfo-l0" found
file "hwinfo-l1" found
file "hwinfo-l2" found
file "loadercode" found
file "mp1.img" found
file "linux" found
Uncompressing Linux... done, booting the kernel.
Linux version 3.6.0-samoa-01844-g1f05798 (ppd@debian) (gcc version 4.3.4 (Buildroot 2010.02) ) #0 Fri, 10 Feb 2023 16:26:07 +0100
cpufreq: initial frequency: 264000 kHz
MAC-1G DMA: 430ab000 - 430ab9ff
MAC addr = 00:08:19:4e:56:2c
eth0: ioaddr: d00d0000, dev: c30ac000
probing samoafb: rc = 0
  DMA = 4F500000->c3a00000, IO =   (null)
UART 1 probing
UART 1 probing OK
UART 2 probing
UART 2 probing OK
UART 3 probing
UART 3 probing OK
pca953x 0-0049: failed reading register
ba315 ba315.0: NAND ID: id[0-3]=’EF A1 00 95’, manu=’Winbond’, dev=’NAND 128MiB 1,8V 8-bit’
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
yaffs: Attempting MTD mount of 31.0,"mtdblock0"
yaffs: yaffs_read_super: is_checkpointed 0
starting pid 398, tty ’’: ’/etc/init.d/rcS’
/etc/init.d/rcS started
Mounting local file systems: ok
rootfs on / type rootfs (rw)
/dev/root on / type yaffs2 (rw,relatime)
proc on /proc type proc (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,mode=600)
tmpfs on /tmp type tmpfs (rw,relatime)
none on /sys type sysfs (rw,relatime)
Mounting usbfs: failed
Terminal is initializing\nPlease wait
...
dropbear is not present
emv-engine-4.3e-with-trace is not present
tim-server-nexo-config_3.1.6.0-1140_arm is not present
mp1-samoa2-eft-sr-prod is not present
Checking for FW updates\nPlease wait

FW is up to date.

Starting Application Monitoring Daemons
Mounting USB stick: failed
starting pid 600, tty ’/dev/ttyCU’: ’/sbin/getty 115200 ttyCU’

samoa login: 

Показано даже приглашение к авторизации. Неплохо! Значит, это определённо журнал загрузки Linux. Во многих встраиваемых системах Linux есть подобная консоль, но чаще всего авторизация отключена полностью или какой-нибудь случайный, жёстко прописанный пароль подставляется либо генерируется при загрузке. Без особых ожиданий я просто из любопытства ввёл в качестве логина «root», и…

samoa login: root
~ #

Подождите-ка! Это что, всё? Я в системе?

Как бы, да. Такова скучная история моего обнаружения root-оболочки. Голой, неприкрытой, root-оболочки. Не потребовалось ни запутанной цепочки эксплойтов, ни подбора паролей… К тому же, несмотря на красный экран с оповещением системы о вскрытии, всё вроде как работает.

Тут вы можете сказать: «Хорошо, но для получения доступа к этой голой root-оболочке нужно вскрыть устройство, что вызовет срабатывание защиты и, по сути, сделает его бесполезным». Но суть в том, что последовательный порт доступен снаружи. К отладочному разъёму можно подключиться без вскрытия устройства через небольшое отверстие на задней панели. Всё, что нужно атакующему — это 30 секунд наедине с устройством, чтобы подключиться к порту, авторизоваться, развернуть вредонос и скрыться. Звучит очень серьёзно.

Доступ к отладочному разъёму и root-оболочке можно получить извне устройства

▍ Так ли всё плохо на самом деле?


Столько навороченных аппаратных решений защиты и всё впустую из-за лени программных инженеров?

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

Зато здесь есть полностью отдельный процессор, называемый mp1, который отвечает за все нюансы «безопасности» — обрабатывает вставленную карту, получает пин-код и показывает информацию на экране. То есть «небезопасная» Linux, работающая на втором процессоре, mp2, обрабатывает только сеть, обновления и бизнес-логику.

По всей видимости, ядро Linux загружается всегда, вне зависимости от состояния защиты. И из него уже загружается безопасное ядро. Для этого Linux загружает в память защищённый загрузчик (loadercode), который, в свою очередь, проверяет, срабатывали ли защиты от вскрытия, и исходя из результата либо показывает красный экран, либо продолжает загружать фактический «защищённый» образ (mp1.img в файловой системе Linux). Этот образ уже как следует зашифрован и подписан двумя сущностями.


Как я на данный момент вижу процесс загрузки Yomani на базе Samoa II ASIC. Первое ядро (небезопасное, прикладное) всегда загружает Linux, которая, в свою очередь, загружает на втором ядре защищённый загрузчик и безопасный образ. Сообщение о вскрытии устройства на экран выводит loadercode. Защищённый образ, который обрабатывает карточку, дисплей и панель клавиш, подобающим образом зашифрован и подписан.

▍ Хронология проекта


  • 14/11/2024 Обнаружил доступ к root-оболочке.
  • 15/11/2024 Уведомил производителя, объявив о том, что опубликую статью через 90 дней.
  • 18/11/2024 Производитель подтвердил получение отчёта.
  • — забыл об этом проекте ---
  • 01/06/2025 Опубликовал статью.

▍ Заключение


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

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

Это был очень интересный проект, и жаль, что у меня не было больше времени для углублённого анализа прошивки и изучения других возможностей. Если вы желаете перенять эстафету, напишите мне (mail@stefan-gloor.ch). Благодарю всех причастных к этому эксперименту людей за их ценный вклад.

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (3)


  1. noknown
    06.06.2025 19:45

    А с имея доступ к этой системе можно подсунуть свой защищенный загрузчик и свой образ защищенной системы? Или имея доступ только снаружи корпуса этого не сделать и для этого нужен доступ к флеш-памяти?


  1. MasterMentor
    06.06.2025 19:45

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

    Стёпа Глур темнит. :) Тем кто в теме - всё сказано однозначно и ясно - и вопросов - нет, остальные - идут лесом.

    Ну и пиэсом: вот что бывает когда разные "кАмАнды" делают разные части дЭвайса. :)

    бабло -> побеждает зло -> жадность -> побеждает бабло :)


  1. Nv317
    06.06.2025 19:45

    Приходилось работать с терминалами этого изготовителя. Есть NDA, поэтому конкретно писать ничего не могу.

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

    Везде где можно они запихнули JSON (например с одним строковым полем), проверки на null писать не хотят. Отправляешь запрос, опечатавшись в имени тега - приложение крашится в NPE не найдя того ключа который должен быть по протоколу. За то уровней абстракций - хоть отбавляй - логический "канал" поверх TCP, поверх (допустим) PPP, который идёт через UART.