Pull to refresh

Comments 4

Мы чуть-чуть подломали экономику бейджей. Стали разбираться, как работает вся эта система, и выяснилось, что

1) в качестве "мозгов" стоит STM32F070F6P6, залоченный от чтения (RDP1);

2) после перепрошивки бейдж не теряет баланс;

3) у всех бейджей одна и та же прошивка.

Также был публично доступнен "банкомат" рядом с киоском мерча за оффкойны (валюту бейджей конференции), который отображал баланс приложенного бейджа. А ещё на бейдже были заботливо выведены и даже подписаны пины SWD - отладочного интерфейса под ARM.

Проследив выводы разъёма для "пополнения" до чипа, предположили, что на него выведен UART. Гипотеза подтвердилась с помощью USB-UART конвертера. Бейдж после включения постоянно шлёт в этот порт на 115200 бод посылками по 40 байт, которые меняются между включениями одного бейджа, но имеют между собой общее начало. А у разных бейджей посылки совершенно отличаются друг от друга.

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

У многих микроконтроллеров от ST с завода есть серийник, расположенный в ROM. Он формируется по координатам чипа на пластине с завода, а также номеру партии. Логично было бы предположить, что этот серийник и используется в качестве исходных данных для формирования пакета на UART. Пожертвовав во благо науки одним бейджем, понизив на нём RDP1 до RDP0 (попутно стерев с него прошивку механизмами безопасности чипа), нашли в ROM 12 байт айди. Впоследствии оказалось, что для чтения айди можно было бы и не понижать RDP, но было уже поздно.

С помощью CyberChef практически сразу выяснилось, что начало пакета - 12 байт - совпадают с SHA1(12 байт id). Более того, работала replay-атака на проверку баланса - заполучив пакет с бейджа, можно было выдать его же на "банкомат" и увидеть баланс оригинального бейджа.

С помощью пары других бейджей выяснили вариативность айдишнков. Из 12 байт менялось всего 4 - 0, 2, 4 и 10, причём диапазон удалось снизить всего до 5 миллионов айди, большинство которых лежало в самом начале диапазона (принадлежали к основной партии чипов). С помощью простейшего скрипта получилось "сбрутить" айди соседнего бейджа, для которого была известна только авторизующая посылка. Но полный алгоритм формирования посылки оставался неизвестным. Можно было бы, конечно, полагаться на случайность и недостаточную валидацию данных сервером баланса, но хотелось большего.

В ходе попыток чтения с помощью JLink по SWD разных бейджей в полевых условиях нам то ли повезло подглитчить питание чипа в момент его запуска (нет), то ли попался экземпляр без защиты, но очередной подопытный показал в утилите JMem валидное состояние флеша без запроса на стирание из-за RDP1. Сразу же сдампили с него прошивку, закинули в Ghidra + SVD loader. Обнаружили ожидаемое - SHA1 из PolarSSL, чтение 12 байт аппаратного айди и многое другое по формированию исследуемой нами подписи. БОльшая часть происходящего была упакована в одну функцию и анализу с наскока не поддалась.

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

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

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

На этом моменте мы обратились к железячным представителям оргов с вопросом, что бы они посчитали взломом экономики. Они сказали, что таковым будет считаться возможность представиться чужим бейджем и даже выдали 12 байт SHA1 от своего личного. По SHA1 и перебором по маске за несколько секунд нашли айди чипа, после чего он был зашит в "вылеченный" бейдж и представлен оргам. Которые подтвердили успех решения задачи и наградили всех причастных приличным количеством оффкойнов.

Привет, кайф, вы большие молодцы. В следующий раз усложним вам задачу :)

https://github.com/AV1ct0r/badges/blob/main/offzone2022/README.md это тоже ваша публикация, получается? Для нас было сюрпризом, кстати, что U_ID в том числе зависит от координаты чипа на пластине.

Публикация не наша, и инструменты в ней другие - там IDA+ST-шное железо и софт, у нас Ghidra и JLink. И там добыча прошивки хардкорнее. Но итоговое решение с патчингом адресов, фактически, такое же.

А перебор со знанием алгоритма U_ID можно было бы реализовать быстрее, ограничив диапазоны отдельных байт до размеров пластины.

Значит, у нас как минимум две команды, которые пришли к результату. Про размер пластины реально красиво. Нужно читать даташиты, там все написано черным по белому, на 1121 странице :)

Sign up to leave a comment.

Articles