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 можно было бы реализовать быстрее, ограничив диапазоны отдельных байт до размеров пластины.
Хабр на конференции OFFZONE 2022: российская BugBounty, кибербез и… текила?