tags: android
Собираем базу номеров с приложения Pootin
Intro
Впервые я рассказал об этом в презентации на 2600-Qazaqstan (08.08.18), на тот момент приложение уже не функционировало и я свободно мог рассказать, как его парсить.
Все вы слышали о GetContact, приложении позволяющем посмотреть, как вы подписаны в телефонной книге у других людей. В свое время оно наделало много шума, например его заблокировали в Казахстане. Сразу же после выхода этого приложения, казахстанские разработчики выпустили свой аналог, под названием Pootin, с тем же функционалом, но с более обширной базой данной пользователей. На то время, защита от реверса в Pootin была на уровень выше, чем в GetContact, что немного удивило. Но ничего страшного!
Анализируя мобильные приложения, мы делаем все по классике, закидываем сертификат burp на эмулятор, и запускаем там приложение. SSL pinning отсутствовал. Функционал приложения прост - вы вводите номер телефона в поле, вам выдается список имен.
Вот так выглядит запрос по конкретному номеру телефона:
Сервер нам отвечает:
В запросе, нас особо интересует следующее:
AUTH TOKEN
- Константное значение в каждом запросе
- Скорее всего, приложение его генерирует, при установке, для каждого отдельного девайса
CSRF TOKEN
- Всегда новый
- Надо понять, как он генерится
Если мы посмотрим внимательней на CSRF токен
Похоже на unix timestamp, не правда ли?
Возьмем первые 10 цифр и сконвертируем
Да, похоже на правду! Если сделать несколько запросов, то можно заметить букву ‘a’ на конце
Итак, что имеем на данный момент?
- Длина всей строки с csrf токеном равна 46
- Первые 10 символов — время запроса
- Последний символ — буква ‘а’
- Откуда берутся остальные 35 символов?
Для этого, обратимся к исходникам. Получить их можно, декомпилировав apk.
Делаем поиск строки ‘csrf’ по исходникам (да, это total commander)
Видим вот такой вот метод AppConstants.INSTANCE.getCsrfToken()
Откроем же наконец исходник AppConstant
Внутри вызывается метод с модификатором native. Модификатор native означает, что реализация метода находится в библиотеках, написанных на других языках. Чтобы работать с такими библиотеками, используется механизм JNI (Java Native Interface). Это значит, что приложение использует внешнюю библиотеку, которая генерит csrf токен.
Делаем поиск по исходникам по слову ‘loadlibrary’ или же ‘lib’, в надежде найти место, где подгружаются какие-нибудь библиотеки.
Или же тупо распаковываем apk и смотрим папку lib
Открываем библиотеку в IDA, открываем окно Functions (Shift + F3), видим нашу функцию
Тело функции
После того, как мы получил UNIX timestamp, мы умножаем его на 1000, чтобы получить миллисекундную часть. Поэтому наш timestamp становится длиной 13 символов.
На предыдущем шаге мы соединили timestamp (включая секунды) с “TtaaTTaaRaUaNTTaaTTaab”. Затем вызываем метод getMd5() из AppConstants, хэшируем результирующую строку. В итоге получаем 32 байта хэша.
Длина всей строки с csrf токеном равна 46 Первые 10 символов — время запроса Последний символ — буква ‘а’ Откуда берутся остальные 35 символов?
Ответ:
- 32 символа — md5 хэш (timestamp + constant string)
- 3 символа — секунды у timestamp
Итоговый скрипт:
salt = r"TTaaTTaaRaUaNTTaaTTaab"
def getSalt():
ts = int(time.time()*1000)
h = hashlib.md5()
h.update(b"%d%s" % (ts, salt.encode()))
return "%d%sa" % (ts, h.hexdigest())