Предисловие

В один прекрасный весенний вечер мне в голову пришла прекрасная идея - попробовать зареверсить приватный API одного из самых крупных шерингов самокатов в РФ. Сразу скажу что на публикацию этого материала мне дал разрешение лично директор компании, но попросил не называть имена и название сервиса. Так же скажу что это не инструкция к действию, ведь уязвимость уже исправили и смысла пытаться её воспроизвести нет.

Цель

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

Подготовка

Отлично, с целью определились, как это реализовать?

Для перехвата пакетов данных которыми обмениваются клиент с сервером нам понадобится сниффер. Сниффер поможет нам влезть в передачу данных посредством Man In The Middle атаки.

Принцип работы MITM атаки.
Принцип работы MITM атаки.

Снифферов полно, но мне нравится HTTP toolkit (он по непонятным мне причинам не доступен в РФ без VPN).

Отлично, сниффер есть, мы все подключили, но вот проблема. Современные приложения используют TLS для обеспечения безопасности данных. Выходит, что не имея приватного ключа мы не сможем прочитать данные, тем более их модифицировать.

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

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

Тут есть два пути:

  1. Если у вас есть root. Использовать встроенный в HTTP toolkit функционал и установить свой сертификат как системный, что убедит все приложения доверять ему.

  2. Если у вас нет 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)


  1. dartraiden
    12.04.2022 21:51
    +9

    HTTP toolkit (он по непонятным мне причинам не доступен в РФ без VPN).

    1 апреля Генпрокуратуре не понравилась страница How to Debug Any CORS Error, 3 апреля она внесена в реестр, ну и соответственно блокируется доступ ко всему домену, раз HTTPS.


    1. moscow_intelligent Автор
      12.04.2022 21:55
      +2

      Вот это да, какой казус. Спасибо за уточнение!


      1. CMEPTbI4
        14.04.2022 14:49

        О, всю ветку потерли... Если что там поверх сайта был попап с разными заявлениями и призывами, что не относятся к теме cors и разработки.


  1. Resurrected
    12.04.2022 21:52
    +1

    Деньги мне в принципе не нужны

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

    Это как, бонусы не за деньги приобретаются?


    1. moscow_intelligent Автор
      12.04.2022 21:53
      +3

      За деньги конечно :) Суть была в том, что взлом был сделан не с целью извлечения выгоды, а "по приколу"


  1. Adjuster2004
    12.04.2022 22:11
    +3

    Илья, а почему в названии статьи Мы?

    Везде по тексту я.


    1. moscow_intelligent Автор
      12.04.2022 22:28
      +1

      Фраза какая то крылатая была, очень похожая на заголовок статьи. Там было "мы" :)


      1. Tyusha
        13.04.2022 10:35
        +3

        Запомнилось из "Аквариума" Виктора Суворова: когда разговариваете с человеком один на один (вербуете), не стоит говорить "мы", т.к. это звучит зловеще. Кто эти неизвестные "мы"? Человек подсознательно не доверяет тому, кого не знает и не видит перед собой. Надо всякий раз говорить "я". Например не "мы вам предлагаем работать на нас", а "я вам предлагаю работать на меня".

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


        1. Vsevo10d
          13.04.2022 15:11
          +1

          Запомнилось из отечественного кинематографа, что когда разговариваете с человеком один на один, не стоит говорить "мы", он начнет ругаться и говорить "Кто мы-то? К кому ты обращаешься во множественном числе - я здесь один!".


  1. gleb_l
    12.04.2022 23:09
    +2

    Ну, допустим, на сервере проверяется валидность мапа модель-тариф, переданного с клиента, и этот фордж теперь заткнули. Но осталась штука гораздо более полезная и крутая - подфорджить lat/long, чтобы можно было удаленно запустить от своего аккаунта поездку на самокате на другом конце города - например, организовав для своего ребенка поездку из школы домой. Как бороться с этим, кроме как проверять подмену сертификата и не работать под угрозой митм вообще?


    1. moscow_intelligent Автор
      12.04.2022 23:55

      Ну, проверкой сертификата тут не обойтись, ведь я могу поставить свой сертификат как root certificate и все будут ему доверять, хотя похожий сервис шеринга уже реализовал защиту от такого. Над обходом этого как раз сейчас работаю :)
      По поводу lat/long - клиент постоянно отправляет запросы в которых узнает наличие самокатов рядом с определенными координатами и если вдруг, клиент зашел в приложение и запросил самокаты рядом с домом в Москве, а потом берет самокат в Ярославле, это немного подозрительно.


    1. edogs
      13.04.2022 00:03
      +8

      удаленно запустить от своего аккаунта поездку на самокате на другом конце города — например, организовав для своего ребенка поездку из школы домой. Как бороться с этим
      А может больше смысла добавить это фичей, чем бороться? В убере и прочих такси было очень удобно вызвать такси не к себе, а к (жене / ребенку / родителям) что бы они ими воспользовались без лишнего гимороя с (оплатой / разбирательством с сервисом) или даже в принципе без смартфона (просто с кнопочным телефоном)?


      1. Daddy_Cool
        13.04.2022 01:06

        А почему "было"? Что случилось с Убером?


        1. edogs
          13.04.2022 02:38

          Давно не пользовались, поэтому не стали употреблять настоящее время на всякий случай, ибо не уверены осталась ли там эта фича.


      1. Formyurik
        13.04.2022 14:27
        +1

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

        А как можно сфотографировать самокат, который находится в другом конце города? (Сфотографировать любой другой это не решение проблемы).

        Справедливости ради (насчет штрафа) расскажу положительную историю про Whoosh: столкнулся в Сочи. Был день России в Сочи и олимпийский парк на дневное время закрыли для самокатов. Вечером открыли и самокаты можно было брать, но внутренние парковки (внутри самого парка) на карте не появились, только снаружи, но попасть туда не получалось, т.к. забор мешал (можно было пройти по надземному переходу и перетащить, но самокат тяжелый). В итоге запарковал максимально близко к парковке, программа сразу предупредила что будет штраф, написал в поддержку и через 3 минуты мне ответили чтобы я не переживал, они проверили, убедились что я прав и поставили пометку в базе что все норм и штрафа не будет.


        1. edogs
          13.04.2022 22:06

          Сфотографировать любой другой это не решение проблемы
          Но зато это отличное объяснение, почему делать фото самоката это по большому счету карго-культ. Там ведь даже не требуется снимать так, что бы серийник был виден. Можно раздолбать самокат в мясо, взять любой другой, сфоткать его и на этом всё — свободен и чист.


          1. Formyurik
            14.04.2022 06:25

            Ну тут тоже скорее всего есть хитрости:

            1) GPS достаточно точный и будет видно часто что это не тот самокат.

            2) Куча сенсоров в самокете, гироскопы, датчики ударов. Думаю что если что-то случится с самокатом - просто посмотрят историю ударов, падений и т.д. И выявят во время аренды это было или нет.


            1. edogs
              14.04.2022 22:05

              1) Дык достаточно убитый с собой взять, а сфоткать целый.
              2) Вряд ли это можно будет предьявить где-то на уровне выше чем «ты че пацан вертай деньги за сломанный самокат», этож не настоящий черный ящик с защитой и вот этим всем.


    1. hMartin
      13.04.2022 00:33
      +3

      спуфинг координат для мобилок - это тривиальная задача, не требует никаких особых навыков)


    1. mentin
      13.04.2022 00:51
      +2

      можно было удаленно запустить от своего аккаунта поездку на самокате на другом конце города

      Не ясно чем это вредит сервису? Деньги они не теряют, зачем что-то блокировать?

      Как бороться с этим, кроме как проверять подмену сертификата и не работать под угрозой митм вообще

      Если с этим надо было бы бороться (сервис каким-то образом терял деньги), то никакие проверки на клиенте не помогут. Клиент может делать хоть certificate pinning, но не поможет. Хакер всегда может просто создать свой клиент и посылать API запросы напрямую. Проверки должны быть на бэкенде, но никак lat/lon не проверить, только отсекать необычное поведение, вроде быстрой смены координат.


      1. Paul_Arakelyan
        13.04.2022 04:33

        Центр торгового зала в Ашане - "Не играйте в Покемон Го в машине!". Проверить - можно, если получить от оператора координаты (вышку, к которой подключён клиент). Но будут и такие варианты, как резкие скачки, если уровня сигнала - нет.


      1. LexxKn
        13.04.2022 06:38

        Подмена координат может помочь в самой поездке. Есть зоны с ограничениями скорости или с запретом. Вот их и можно обойти.


        1. moscow_intelligent Автор
          13.04.2022 06:43
          +2

          Насколько я понял, там проверяются координаты самоката, а не юзера. А самокат это уже отдельная железка.


    1. x67
      13.04.2022 10:12
      +1

      Никак. Тут даже технических скиллов не надо, просто включите режим отладки андроид и введите координаты вручную, будет тоже самое

      Да и смысла особого нет в этом, так как можно передать и телефон и просто авторизовать приложение на устройстве ребенка. Это лишь защита от дурака. Все равно юридически вы несете ответственность за то, что происходит с самокатом. Фактически конечно не всегда, но это другой вопрос


  1. inscriptios
    12.04.2022 23:45
    +1

    Но осталась штука гораздо более полезная и крутая - подфорджить lat/long

    Гораздо более крутая, чем кататься со скидкой 80%? ????


  1. v1000
    13.04.2022 00:29
    +9

    фикс данной уязвимости достаточно прост

    Как всегда простое правило - сервер не должен верить ничему на стороне клиента.


  1. Alexsey
    13.04.2022 02:36
    +4

    Параметр withInsurance у order/make с потрохами выдает о ком идет речь. :) По крайней мере не помню чтобы у остальных такая галка была. В принципе респект им за реакцию, не первый раз слышу о том что у них руководство весьма приземленное.


    1. moscow_intelligent Автор
      13.04.2022 06:32
      +1

      Ну не то что бы выдаёт, я знаю как минимум 2 сервиса в которых есть страховка


  1. olegtsss
    13.04.2022 04:14

    «Подменить сертификат просто, но Android приложения зачастую не очень хотят отправлять данные используя наш сертификат, ведь они ему не доверяют» — что-то я не понял историю с сертификатами. Вы, наверное, имеете дело с прокси HTTPS трафика, когда дополнительный софт открывает шифрованную сессию (end-to-end) с удаленным сервером («по его правилам»), а этот же дополнительный софт открывает вторую закрытую сессию уже с вашим браузером (мобильным приложением). MiTM. И вы устанавливаете в качестве доверенного сертификата в операционную систему именно сертификат этого доп софта.


    1. vikarti
      13.04.2022 07:59
      +1

      «Подменить сертификат просто, но Android приложения зачастую не очень хотят отправлять данные используя наш сертификат, ведь они ему не доверяют» — что-то я не понял историю с сертификатами.

      Видимо речь про то, что можно сделать так, что сертификату мало быть просто доверенным, мало быть даже системным а надо быть выписанным конкретными CA (возможно — своими) или вообще будет работать только конкретный сертификат.


      Правда эту проблему тоже решают — https://habr.com/ru/post/559722/ https://habr.com/ru/post/495682/#comment_21463074


    1. ifap
      13.04.2022 13:06
      +1

      Я вот тоже не уловил сути финта с сертификатами. Сервер не умеет в EMS? Пичаль, но легко фиксится. Сервер не валидирует данные, приходящие с клиента? Тогда можно было просто передавать: начало аренды - 12:20, окончание - 12:21, а самому кататься сутками напролет хоть даже и по дорогому тарифу.


      1. airPurifier
        13.04.2022 18:13

        передавать: начало аренды - 12:20, окончание - 12:21, а самому кататься сутками напролет хоть даже и по дорогому тарифу.

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


  1. s37
    13.04.2022 09:55
    +6

    Мне ответили буквально через 10 минут и дали контакт их директора, сказали связаться с ним.

    Я изложил суть ему, он выразил мне благодарность

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


  1. Trigger1985
    13.04.2022 23:31
    +1

    Закрыли одну маленькую лазейку. Лучше напишите статью "Как защититься от подмены сертификата".


    1. moscow_intelligent Автор
      13.04.2022 23:32
      +1

      Ответ на этот вопрос простой - никак :)

      Поставите ssl pin, можно обойти через frida. Поменяете манифест, можно обойти через apk-mitm