Предисловие
В один прекрасный весенний вечер мне в голову пришла прекрасная идея - попробовать зареверсить приватный API одного из самых крупных шерингов самокатов в РФ. Сразу скажу что на публикацию этого материала мне дал разрешение лично директор компании, но попросил не называть имена и название сервиса. Так же скажу что это не инструкция к действию, ведь уязвимость уже исправили и смысла пытаться её воспроизвести нет.
Цель
Для начала определим цель нашего исследования - понять как происходит взаимодействие с сервером, как запускается самокат и можно ли в этот процесс вмешаться с целью извлечения выгоды.
Подготовка
Отлично, с целью определились, как это реализовать?
Для перехвата пакетов данных которыми обмениваются клиент с сервером нам понадобится сниффер. Сниффер поможет нам влезть в передачу данных посредством Man In The Middle атаки.
Снифферов полно, но мне нравится HTTP toolkit (он по непонятным мне причинам не доступен в РФ без VPN).
Отлично, сниффер есть, мы все подключили, но вот проблема. Современные приложения используют TLS для обеспечения безопасности данных. Выходит, что не имея приватного ключа мы не сможем прочитать данные, тем более их модифицировать.
Тут нам на выручку приходит процесс подмены сертификатов в Android. Если вкратце, мы просто добавляем в систему наш сертификат, ключи от которого нам известны заранее. Соответственно, все что передается с использованием этого сертификата можно расшифровать
Подменить сертификат просто, но Android приложения зачастую не очень хотят отправлять данные используя наш сертификат, ведь они ему не доверяют.
Тут есть два пути:
Если у вас есть root. Использовать встроенный в HTTP toolkit функционал и установить свой сертификат как системный, что убедит все приложения доверять ему.
Если у вас нет root. Поменять настройки приложения путем его декомпиляции. Для этого можно использовать apkmitm.
Так как на моём телефоне есть root права, я пошёл по первому пути. Я просто запустил HTTP toolkit, подключился к телефону и он сам установил свой сертификат как доверенный. Теперь все приложения в которых нет защиты от подмены сертификатов будут отправлять данные используя мой сертификат.
Reverse engineering
Отлично, мы все подготовили, сертификаты подменили, сниффер настроили. Пора начинать реверсить.
Первым делом, после открытия приложения мы видим следующее.
Тут мы видим авторизацию, получение информации о моделях самокатов и наличии у меня подписки на их сервис, так же есть запрос на то, в каких городах доступен этот сервис.
На самом деле, там целая куча запросов и разбирать каждый из них мы будем до утра.
Так что, в целях сокращения объема статьи я сразу перейду к тому запросу, который позволил мне взломать сервис и получить за это свой bug bounty.
Меня привлек запрос /gatewayclient/api/v1/order/make
Этот запрос на начало аренды самоката и в нём на самом деле немного параметров. Помимо необходимого токена авторизации и прочих скучных заголовков там есть всего 6 параметров. locationLat, locationLng, isQrCode, rateId, Identifier и withInsurance
locationLat и locationLng
это координаты пользователя, они там находятся для того что бы пользователь не брал самокаты которые слишком далеко от него
isQrCode и withInsurance
это логические значения (true или false) которые отвечают за то, взял ли пользователь самокат по qr коду и оформил ли он страховку поездки.
И самые интересные параметры - Identifier и rateId
Identifier
- номер самоката
rateId
- id тарифа по которому мы берем самокат
Меня очень зацепил rateId
так как в теории, его можно подменить и взять самокат по другому тарифу.
Я решил посмотреть какие у них есть тарифы. Оказалось, что действительно, для каждой цены есть свой rateId
Например
5 р/м |
j123id901k |
8р/м |
1asda2dasd |
10 р/м |
2ad32ad3a4 |
Все id я выдумал, что бы не показывать реальные данные, но расклад там примерно такой же.
Нереальное веселье
Я тут же побежал писать маленький скрипт на основе модуля mitmproxy для Python. Этот модуль позволяет ловить запросы и изменять их на ходу. Я написал небольшой аддон для этого mitmproxy который подменял координаты на координаты рядом с самокатом, что бы можно было взять самокат где угодно. И добавил подмену тарифа, на самый дешёвый. Как только софт был готов, я быстренько залил его на телефон и запустил через Termux (это такой очень прикольный эмулятор терминала под Android).
Я подбежал к самокату, поднял прокси, и взял его в аренду. Посмотрел на телефон и понял, что я взял самокат в аренду за 2 рубля в минуту вместо положенных 10.
Радости были полные штаны, я в тот вечер накатался на этом самокате почти час, заплатив за это всего лишь 120 рублей, вместо положенных 600+
Bug report
Я конечно был безумно рад своему успеху, но мы же все порядочные люди и white hat хакеры. Поэтому я еще чуть-чуть покатался на дешевых самокатах и написал email в тех поддержку этого сервиса, в котором изложил всю суть уязвимости и дал предложения о том, как это исправить.
Мне ответили буквально через 10 минут и дали контакт их директора, сказали связаться с ним.
Я изложил суть ему, он выразил мне благодарность и спросил, чего я хочу в качестве bug bounty. Деньги мне в принципе не нужны, да и мерч какой-то тоже, так что я попросил просто начислить мне побольше бонусов, ведь я сам пользуюсь их сервисом. Через 10 минут у меня уже были мои драгоценные бонусы, которых мне скорее всего хватит на пару лет вперёд.
Как это предотвратить? Фикс
Вообще, фикс данной уязвимости достаточно прост. Все что нужно сделать, это проверить доступен ли переданный пользователем тариф для того самоката, который он берет и если нет, отказать ему в аренде.
Заключение
В заключении скажу, что на самом деле уязвимость лежит на поверхности, но мне пришлось пройти достаточно длинный путь, что бы до неё добраться и конечным результатом я остался доволен. Надеюсь этот кейс даст вам хотя бы примерное понимание о том, как тестируют сервисы на уязвимости и может кто то из читателей сможет внести свой вклад в улучшение их любимого сервиса.
Всем спасибо за внимание, удачи.
Всегда ваш, @moscow_intelligent
Комментарии (38)
Resurrected
12.04.2022 21:52+1Деньги мне в принципе не нужны
так что я попросил просто начислить мне побольше бонусов, ведь я сам пользуюсь их сервисом.
Это как, бонусы не за деньги приобретаются?
moscow_intelligent Автор
12.04.2022 21:53+3За деньги конечно :) Суть была в том, что взлом был сделан не с целью извлечения выгоды, а "по приколу"
Adjuster2004
12.04.2022 22:11+3Илья, а почему в названии статьи Мы?
Везде по тексту я.
moscow_intelligent Автор
12.04.2022 22:28+1Фраза какая то крылатая была, очень похожая на заголовок статьи. Там было "мы" :)
Tyusha
13.04.2022 10:35+3Запомнилось из "Аквариума" Виктора Суворова: когда разговариваете с человеком один на один (вербуете), не стоит говорить "мы", т.к. это звучит зловеще. Кто эти неизвестные "мы"? Человек подсознательно не доверяет тому, кого не знает и не видит перед собой. Надо всякий раз говорить "я". Например не "мы вам предлагаем работать на нас", а "я вам предлагаю работать на меня".
Поэтому давно подмечаю, что какие-нибудь фрилансеры или недокомпании на своих сайтах всегда говорят "мы", хотя очевидно, что за этим стоит всего лишь один человек. Видимо хотят придать себе солидности, выдать себя за корпорацию.
Vsevo10d
13.04.2022 15:11+1Запомнилось из отечественного кинематографа, что когда разговариваете с человеком один на один, не стоит говорить "мы", он начнет ругаться и говорить "Кто мы-то? К кому ты обращаешься во множественном числе - я здесь один!".
gleb_l
12.04.2022 23:09+2Ну, допустим, на сервере проверяется валидность мапа модель-тариф, переданного с клиента, и этот фордж теперь заткнули. Но осталась штука гораздо более полезная и крутая - подфорджить lat/long, чтобы можно было удаленно запустить от своего аккаунта поездку на самокате на другом конце города - например, организовав для своего ребенка поездку из школы домой. Как бороться с этим, кроме как проверять подмену сертификата и не работать под угрозой митм вообще?
moscow_intelligent Автор
12.04.2022 23:55Ну, проверкой сертификата тут не обойтись, ведь я могу поставить свой сертификат как root certificate и все будут ему доверять, хотя похожий сервис шеринга уже реализовал защиту от такого. Над обходом этого как раз сейчас работаю :)
По поводу lat/long - клиент постоянно отправляет запросы в которых узнает наличие самокатов рядом с определенными координатами и если вдруг, клиент зашел в приложение и запросил самокаты рядом с домом в Москве, а потом берет самокат в Ярославле, это немного подозрительно.
edogs
13.04.2022 00:03+8удаленно запустить от своего аккаунта поездку на самокате на другом конце города — например, организовав для своего ребенка поездку из школы домой. Как бороться с этим
А может больше смысла добавить это фичей, чем бороться? В убере и прочих такси было очень удобно вызвать такси не к себе, а к (жене / ребенку / родителям) что бы они ими воспользовались без лишнего гимороя с (оплатой / разбирательством с сервисом) или даже в принципе без смартфона (просто с кнопочным телефоном)?Daddy_Cool
13.04.2022 01:06А почему "было"? Что случилось с Убером?
edogs
13.04.2022 02:38Давно не пользовались, поэтому не стали употреблять настоящее время на всякий случай, ибо не уверены осталась ли там эта фича.
Formyurik
13.04.2022 14:27+1Предполагаю что логика в том, что после окончания аренды Вы обязаны сфотографировать самокат (то, как Вы его припарковали) для подтверждения того что он целый и что Вы припарковали его правильно. В противном случае (в случае неправильной парковки) будете платить 500 руюлей штрафа.
А как можно сфотографировать самокат, который находится в другом конце города? (Сфотографировать любой другой это не решение проблемы).
Справедливости ради (насчет штрафа) расскажу положительную историю про Whoosh: столкнулся в Сочи. Был день России в Сочи и олимпийский парк на дневное время закрыли для самокатов. Вечером открыли и самокаты можно было брать, но внутренние парковки (внутри самого парка) на карте не появились, только снаружи, но попасть туда не получалось, т.к. забор мешал (можно было пройти по надземному переходу и перетащить, но самокат тяжелый). В итоге запарковал максимально близко к парковке, программа сразу предупредила что будет штраф, написал в поддержку и через 3 минуты мне ответили чтобы я не переживал, они проверили, убедились что я прав и поставили пометку в базе что все норм и штрафа не будет.
edogs
13.04.2022 22:06Сфотографировать любой другой это не решение проблемы
Но зато это отличное объяснение, почему делать фото самоката это по большому счету карго-культ. Там ведь даже не требуется снимать так, что бы серийник был виден. Можно раздолбать самокат в мясо, взять любой другой, сфоткать его и на этом всё — свободен и чист.Formyurik
14.04.2022 06:25Ну тут тоже скорее всего есть хитрости:
1) GPS достаточно точный и будет видно часто что это не тот самокат.
2) Куча сенсоров в самокете, гироскопы, датчики ударов. Думаю что если что-то случится с самокатом - просто посмотрят историю ударов, падений и т.д. И выявят во время аренды это было или нет.
edogs
14.04.2022 22:051) Дык достаточно убитый с собой взять, а сфоткать целый.
2) Вряд ли это можно будет предьявить где-то на уровне выше чем «ты че пацан вертай деньги за сломанный самокат», этож не настоящий черный ящик с защитой и вот этим всем.
hMartin
13.04.2022 00:33+3спуфинг координат для мобилок - это тривиальная задача, не требует никаких особых навыков)
mentin
13.04.2022 00:51+2можно было удаленно запустить от своего аккаунта поездку на самокате на другом конце города
Не ясно чем это вредит сервису? Деньги они не теряют, зачем что-то блокировать?
Как бороться с этим, кроме как проверять подмену сертификата и не работать под угрозой митм вообще
Если с этим надо было бы бороться (сервис каким-то образом терял деньги), то никакие проверки на клиенте не помогут. Клиент может делать хоть certificate pinning, но не поможет. Хакер всегда может просто создать свой клиент и посылать API запросы напрямую. Проверки должны быть на бэкенде, но никак lat/lon не проверить, только отсекать необычное поведение, вроде быстрой смены координат.
Paul_Arakelyan
13.04.2022 04:33Центр торгового зала в Ашане - "Не играйте в Покемон Го в машине!". Проверить - можно, если получить от оператора координаты (вышку, к которой подключён клиент). Но будут и такие варианты, как резкие скачки, если уровня сигнала - нет.
LexxKn
13.04.2022 06:38Подмена координат может помочь в самой поездке. Есть зоны с ограничениями скорости или с запретом. Вот их и можно обойти.
moscow_intelligent Автор
13.04.2022 06:43+2Насколько я понял, там проверяются координаты самоката, а не юзера. А самокат это уже отдельная железка.
x67
13.04.2022 10:12+1Никак. Тут даже технических скиллов не надо, просто включите режим отладки андроид и введите координаты вручную, будет тоже самое
Да и смысла особого нет в этом, так как можно передать и телефон и просто авторизовать приложение на устройстве ребенка. Это лишь защита от дурака. Все равно юридически вы несете ответственность за то, что происходит с самокатом. Фактически конечно не всегда, но это другой вопрос
inscriptios
12.04.2022 23:45+1Но осталась штука гораздо более полезная и крутая - подфорджить lat/long
Гораздо более крутая, чем кататься со скидкой 80%? ????
v1000
13.04.2022 00:29+9фикс данной уязвимости достаточно прост
Как всегда простое правило - сервер не должен верить ничему на стороне клиента.
Alexsey
13.04.2022 02:36+4Параметр withInsurance у order/make с потрохами выдает о ком идет речь. :) По крайней мере не помню чтобы у остальных такая галка была. В принципе респект им за реакцию, не первый раз слышу о том что у них руководство весьма приземленное.
moscow_intelligent Автор
13.04.2022 06:32+1Ну не то что бы выдаёт, я знаю как минимум 2 сервиса в которых есть страховка
olegtsss
13.04.2022 04:14«Подменить сертификат просто, но Android приложения зачастую не очень хотят отправлять данные используя наш сертификат, ведь они ему не доверяют» — что-то я не понял историю с сертификатами. Вы, наверное, имеете дело с прокси HTTPS трафика, когда дополнительный софт открывает шифрованную сессию (end-to-end) с удаленным сервером («по его правилам»), а этот же дополнительный софт открывает вторую закрытую сессию уже с вашим браузером (мобильным приложением). MiTM. И вы устанавливаете в качестве доверенного сертификата в операционную систему именно сертификат этого доп софта.
vikarti
13.04.2022 07:59+1«Подменить сертификат просто, но Android приложения зачастую не очень хотят отправлять данные используя наш сертификат, ведь они ему не доверяют» — что-то я не понял историю с сертификатами.
Видимо речь про то, что можно сделать так, что сертификату мало быть просто доверенным, мало быть даже системным а надо быть выписанным конкретными CA (возможно — своими) или вообще будет работать только конкретный сертификат.
Правда эту проблему тоже решают — https://habr.com/ru/post/559722/ https://habr.com/ru/post/495682/#comment_21463074
ifap
13.04.2022 13:06+1Я вот тоже не уловил сути финта с сертификатами. Сервер не умеет в EMS? Пичаль, но легко фиксится. Сервер не валидирует данные, приходящие с клиента? Тогда можно было просто передавать: начало аренды - 12:20, окончание - 12:21, а самому кататься сутками напролет хоть даже и по дорогому тарифу.
airPurifier
13.04.2022 18:13передавать: начало аренды - 12:20, окончание - 12:21, а самому кататься сутками напролет хоть даже и по дорогому тарифу.
Сомневаюсь: наиболее вероятно, окончание конкретной поездки лочит конкретный самокат до начала следующей.
s37
13.04.2022 09:55+6Мне ответили буквально через 10 минут и дали контакт их директора, сказали связаться с ним.
Я изложил суть ему, он выразил мне благодарность
Вроде бы абсолютно адекватная реакция адекватных людей, но в наше время это почему-то все еще вызывает какой-то "шок" что-ли, что люди ответили, не начали орать, не угрожали, не пытались решить на своём уровне (чтобы директор не узнал о косяке), а сразу передали проблему на тот уровень, где её могут решить.
Trigger1985
13.04.2022 23:31+1Закрыли одну маленькую лазейку. Лучше напишите статью "Как защититься от подмены сертификата".
moscow_intelligent Автор
13.04.2022 23:32+1Ответ на этот вопрос простой - никак :)
Поставите ssl pin, можно обойти через frida. Поменяете манифест, можно обойти через apk-mitm
dartraiden
1 апреля Генпрокуратуре не понравилась страница How to Debug Any CORS Error, 3 апреля она внесена в реестр, ну и соответственно блокируется доступ ко всему домену, раз HTTPS.
moscow_intelligent Автор
Вот это да, какой казус. Спасибо за уточнение!
CMEPTbI4
О, всю ветку потерли... Если что там поверх сайта был попап с разными заявлениями и призывами, что не относятся к теме cors и разработки.