Статья OAuth уязвимости WeChat Mini-Programs: три вектора захвата аккаунта через мисконфигурацию OBA

Смартфон экраном вниз на тёмном антистатическом коврике излучает бирюзовое свечение. Рядом отладочный зонд подключён к консоли с перехваченным трафиком.


Динамический анализ 44 273 WeChat и 2 721 Baidu Mini-Programs выявил 1 834 случая кривой реализации OAuth-подобной авторизации - 619 приложений содержали комбинацию нескольких дыр одновременно (Shi et al., "MiniCAT: Understanding and Detecting OAuth Access Control Threats in Mini-Programs», USENIX Security 2024). Среди пострадавших - государственные сервисы и медицинские Mini-Programs, через которые утекали национальные ID и медицинские записи граждан КНР. Результаты подтверждены присвоением идентификаторов CNVD/CNNVD (конкретные ID не раскрыты публично).

В русскоязычном пространстве эта тема - белое пятно. Все существующие материалы крутятся вокруг стандартного OAuth 2.0: redirect_uri bypass, token theft через Slack и Facebook. Но проприетарный протокол суперприложений - совершенно другой зверь, и его никто не разбирал. Ниже - три конкретных вектора account takeover в WeChat Mini-Programs: от модели угроз до PoC-логики и инструментария динамического анализа.

Как устроена авторизация в WeChat Mini-Programs и почему это не стандартный OAuth 2.0​

1783788490772.webp

Разработчики привыкли называть механизм входа в Mini-Programs "OAuth", но это вводит в заблуждение. WeChat использует проприетарный протокол - OAuth-based Authentication (OBA), и он принципиально отличается от RFC 6749.

В классическом OAuth 2.0 flow участвуют три стороны: Resource Owner, Authorization Server и Client Application. Клиент получает authorization code через redirect_uri, обменивает его на access_token с помощью client_secret и дальше ходит с токеном к API ресурсного сервера. Основная attack surface - манипуляция redirect_uri (Open Redirect -> Token Theft), отсутствие или предсказуемость state-параметра, слабая валидация PKCE.

В WeChat Mini-Programs архитектура другая. Mini-Program выполняется внутри уже аутентифицированного суперприложения (по отчёту Tencent за Q3 2024 - около 1,38 млрд combined MAU Weixin/WeChat). Workflow OBA:
  1. Фронтенд Mini-Program вызывает wx.login(), получая временный одноразовый code (не authorization code в терминах OAuth 2.0 - у него другой lifecycle)
  2. Бэкенд разработчика отправляет code вместе с appid и appsecret на эндпоинт WeChat code2Session (server-to-server)
  3. WeChat возвращает openid (уникальный идентификатор пользователя в рамках конкретного Mini-Program), unionid (идентификатор в рамках всех приложений одного разработчика) и session_key (криптографический ключ сессии для расшифровки пользовательских данных)
  4. Бэкенд разработчика создаёт сессию и отправляет фронтенду session token
Критическое отличие: redirect_uri здесь нет - Mini-Program живёт внутри WebView суперприложения. Стандартные чеклисты OAuth-аудита (проверка redirect_uri, state, PKCE) бесполезны. Attack surface смещается на обработку session_key и openid на стороне бэкенда разработчика, клиент-серверное взаимодействие между фронтендом Mini-Program и сервером разработчика, а также криптографические операции с данными пользователя.

Проприетарная природа протокола делает WeChat OBA слепым пятном для тех, кто привык к стандартному OAuth 2.0. И это не академическая проблема - это реальная attack surface, которую мало кто проверяет.

Модель угроз: кто атакует и что ему доступно​

[Применимо: внешний пентест Mini-Program, black-box / bug bounty]

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

Атакующий может: создать собственный Mini-Program и получить appid/appsecret; перехватывать HTTPS-трафик между фронтендом Mini-Program жертвы и бэкендом разработчика (через mitmproxy/Burp Suite с настроенным trust store на рутованном устройстве); анализировать и модифицировать клиентский JavaScript-код Mini-Program (через WeChat DevTools или jadx для деобфускации); слать произвольные запросы к API бэкенда разработчика.

Атакующий не может (при корректной реализации): перехватить трафик между бэкендом разработчика и серверами WeChat (server-to-server вызов code2Session); подделать code от wx.login() - он одноразовый, TTL порядка 5 минут согласно документации code2Session, привязан к appid Mini-Program и сессии wx.login(), invalidated после первого вызова code2Session (повторный вызов возвращает errcode 40163 - code been used, см. developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html); получить session_key напрямую от WeChat без знания appsecret.

Вся attack surface возникает из-за ошибок на стороне сторонних разработчиков, а не платформы WeChat. Платформа предоставляет API - разработчики криво их реализуют. Принципиальное отличие от стандартных OAuth-уязвимостей, где проблема часто в самом Authorization Server.

Вектор 1 - Client-Side Identity Forgery: утечка credentials на фронтенд​

Суть: бэкенд разработчика возвращает openid и/или session_key прямо в HTTP-ответе фронтенду Mini-Program. Атакующий перехватывает эти данные и подставляет openid жертвы для авторизации под чужим аккаунтом.

Механика уязвимости. В корректной реализации вызов code2Session идёт server-to-server: бэкенд получает openid + session_key от WeChat, создаёт сессию и возвращает фронтенду только непрозрачный session token (cookie или JWT). Фронтенд никогда не видит ни openid, ни session_key.

В уязвимой реализации бэкенд сливает эти данные прямо в теле ответа:
JSON:
{
  "status": "ok",
  "openid": "oXyz123abc456def789",
  "session_key": "tK8dN2sLm...",
  "user_token": "eyJhbGciOi..."
}
Когда я впервые увидел такое в трафике - не поверил. Но по данным MiniCAT, это самый распространённый вектор из трёх.

Цепочка эксплуатации. Атакующий запускает целевой Mini-Program, проходит авторизацию и перехватывает через Burp Suite собственный openid из ответа. В дальнейших запросах к API бэкенда видит, что openid передаётся как параметр аутентификации (в теле POST или query-параметре). Подстановка чужого openid приводит к авторизации от имени жертвы - если бэкенд не привязывает openid к серверной сессии, запрос проходит без дополнительных проверок.

Предусловия: бэкенд передаёт openid на фронтенд в ответе на логин-запрос; openid используется как единственный идентификатор пользователя без привязки к серверной сессии; нет дополнительной верификации (подпись запроса, привязка к device fingerprint).

Когда техника НЕ работает: разработчик реализовал серверный session management и не раскрывает openid клиенту; Mini-Program не имеет собственного бэкенда (чисто статические информационные приложения); бэкенд проверяет code при каждом запросе, а не полагается на ранее полученный openid.

По MITRE ATT&CK - комбинация Steal Application Access Token (T1528, Credential Access): перехват openid/session_key из трафика, и Valid Accounts (T1078): использование украденного идентификатора как валидных учётных данных.

Вектор 2 - Статические идентификаторы и перманентный захват аккаунта​

Суть: Mini-Program использует для аутентификации статический идентификатор (openid или unionid) вместо динамически генерируемого токена сессии. Атакующий, однажды узнав идентификатор жертвы, получает постоянный доступ к аккаунту - без ограничения по времени.

openid не меняется между сессиями для одного пользователя в одном Mini-Program. Если бэкенд принимает openid напрямую как ключ аутентификации (вместо короткоживущего session token), атакующий получает перманентный доступ. По сути - вечный пароль, который нельзя сменить.

Ситуация становится хуже при использовании unionid - идентификатора, общего для всех Mini-Programs одного разработчика. Компрометация unionid в одном приложении даёт доступ ко всем приложениям этого разработчика. Это уже не просто account takeover - это lateral movement через Application Access Token (T1550.001) внутри хозяйства одного вендора.

Разница с Вектором 1: в первом случае проблема - утечка openid через сетевой трафик. Здесь проблема глубже: даже если openid получен легитимным путём (утечка базы данных, социальная инженерия, перехват трафика другого Mini-Program того же разработчика через unionid), отсутствие ротации сессий делает его вечным ключом к аккаунту.

Предусловия: openid или unionid используется как единственный фактор аутентификации; нет серверной сессии с ротацией токенов; бэкенд не привязывает аутентификацию к session_key (который обновляется при каждом вызове wx.login()).

Когда техника НЕ работает: разработчик реализовал нормальный session management с короткоживущими JWT/cookie, привязанными к session_key; бэкенд требует свежий code от wx.login() при каждом критическом действии; Mini-Program не хранит пользовательских данных.

По OWASP - A05:2021 Security Misconfiguration: архитектурная ошибка при проектировании auth-flow.

Вектор 3 - Криптографический дефект: утечка session_key через Initialization Vector​

Суть: платформенный дефект позволяет восстановить session_key через анализ Initialization Vector (IV) в зашифрованных данных пользователя. Это открывает расшифровку чувствительных данных (номер телефона, профиль) и подделку личности.

Механика уязвимости. Когда Mini-Program запрашивает чувствительные данные (номер телефона через getPhoneNumber, информацию профиля), WeChat возвращает их в зашифрованном виде - AES-128-CBC с session_key в роли ключа. Данные передаются вместе с encryptedData и iv.

В корректной криптографической реализации IV должен генерироваться случайно и быть независимым от ключа. Исследование обнаружило, что на платформе Baidu (порядка 600–700 млн MAU) IV переиспользует часть session_key вместо генерации случайного значения. Что это значит на практике: атакующий получает IV из ответа (он передаётся открыто), IV содержит информацию о session_key, и пространство перебора для восстановления полного ключа существенно сокращается. Красивый фантик шифрования - а внутри подсказка к ключу. По OWASP - A02:2021 Cryptographic Failures.

Для WeChat ситуация несколько лучше - IV генерируется отдельно от session_key. Но если session_key утёк через Вектор 1, атакующий расшифровывает все пользовательские данные, включая номер телефона - а это уже вектор для account takeover через SMS-подтверждение на других платформах или внутри WeChat.

Предусловия: для Baidu - доступ к зашифрованным данным с IV (перехват трафика); для WeChat - утечка session_key через Вектор 1 или 2; Mini-Program запрашивает чувствительные данные (телефон, профиль).

Когда техника НЕ работает: дефект с IV обнаружен на Baidu, не на WeChat. Для WeChat Mini-Programs этот вектор работает только в комбинации с утечкой session_key - сам по себе он не эксплуатируется. По MITRE ATT&CK - Exploitation for Credential Access (T1212).

Сравнение векторов и место в kill chain​

ПараметрВектор 1: Client-Side ForgeryВектор 2: Статические IDВектор 3: Крипто-дефект
Attack SurfaceHTTP-ответ бэкенда фронтендуAPI бэкенда (session management)Зашифрованные данные (encryptedData + IV)
ПредусловияУтечка openid/session_key в трафикеОтсутствие ротации сессийДефект IV (Baidu) или утечка session_key
ИмпактFull account takeoverPersistent account takeoverРасшифровка PII + account takeover
Сложность эксплуатацииНизкая - перехват и replayСредняя - нужен openid жертвыВысокая - криптоанализ + чейнинг
MITRE ATT&CKT1528 + T1078T1078T1212
OWASP 2021A05 Security MisconfigurationA05 Security MisconfigurationA02 Cryptographic Failures

Kill chain позиция. Все три вектора работают на стыке Initial Access и Credential Access:
Что происходит после account takeover. Захват аккаунта Mini-Program - не конечная точка. В зависимости от функциональности: финансовые Mini-Programs дают доступ к балансу и транзакциям, медицинские - к национальным ID и медицинским записям (подтверждено исследованием), государственные сервисы - к персональным данным граждан, e-commerce - к адресам доставки и привязанным платёжным методам.

Кросс-платформенная картина. Аналогичные мисконфигурации воспроизводятся не только в WeChat, но и в Baidu, Alipay и TikTok Mini-Programs. Это системная проблема среды суперприложений, где платформа предоставляет API, а тысячи сторонних разработчиков с разным уровнем компетенции собирают авторизацию самостоятельно.

Динамический анализ Mini-Programs: инструменты и методология​

1783788614734.webp

Требования к окружению:
  • ОС: Windows 10/11, macOS 12+, или Ubuntu 22.04+
  • RAM: минимум 8 ГБ (16 ГБ рекомендуется для одновременной работы эмулятора и прокси)
  • WeChat DevTools: текущая версия (developers.weixin.qq.com)
  • Burp Suite Professional >= 2024.x (Community Edition ограничен в кастомных расширениях для wx-payload)
  • mitmproxy >= 10.x
  • jadx >= 1.5 для декомпиляции обфусцированного JavaScript
  • Python 3.10+ (requests, pycryptodome для работы с AES)
  • Android-устройство с root или эмулятор (для перехвата трафика WeChat)
  • Сетевые условия: онлайн (нужен доступ к серверам WeChat и бэкенду тестируемого Mini-Program)
Почему статический анализ не справляется. Исследователи фреймворка MiniCAT (Shi et al., USENIX Security 2024, USENIX Security '24) - одного из первых специализированных инструментов для масштабного анализа OBA-мисконфигураций - показали, что статический анализ JavaScript-кода Mini-Program (файлы .js, .wxml, .wxss) пропускает большинство уязвимостей по двум причинам. Первая - обфускация: production Mini-Programs минифицированы, jadx восстанавливает структуру частично, но бизнес-логику авторизации из статического кода вытащить сложно. Вторая - runtime-природа уязвимостей: OBA-мисконфигурации проявляются только при реальном взаимодействии клиента с сервером. Какие данные бэкенд возвращает в ответе на code2Session, как обрабатывает openid при повторной аутентификации - это видно только в трафике. SAST тут мёртв.

Методология ручного пентеста Mini-Program OBA:
  1. Настройка прокси. На Android установка CA-сертификата в system trust store требует root - Android 7+ с targetSdkVersion>=24 по умолчанию не доверяет user-installed CA (Network Security Config), и WeChat собран с этим ограничением. Альтернатива: Frida-скрипт для отключения SSL verification в WeChat runtime (работает без модификации system store, но требует root/jailbreak). На iOS - профиль конфигурации через Settings.
  2. Идентификация OBA-запросов. Открываем целевой Mini-Program и фильтруем в логе прокси запросы, содержащие параметры code, openid, session_key, encryptedData, iv. Маркер OBA-flow - POST-запрос сразу после загрузки Mini-Program с code от wx.login() в теле.
  3. Проверка утечки (Вектор 1). Анализируем ответ бэкенда на логин-запрос. Если в JSON-ответе присутствуют ключи openid или session_key - уязвимость подтверждена. Автоматизация через mitmproxy addon:
Python:
# mitmproxy addon: обнаружение утечки OBA-credentials
# (пример для демонстрации концепции)
from mitmproxy import http
import json

def response(flow: http.HTTPFlow):
    if not (flow.response and flow.response.content): return
    try:
        data = json.loads(flow.response.content)
        leaked = {k: data[k] for k in ("openid","session_key","unionid") if k in data}
        if leaked: print(f"[OBA LEAK] {flow.request.url}: {leaked}")
    except: pass
  1. Тестирование подмены (Вектор 2). В Burp Repeater повторяем запрос аутентификации с подменённым openid. Если сервер возвращает данные другого пользователя без дополнительных проверок - подтверждён Вектор 2.
  2. Проверка криптографии (Вектор 3). Если Mini-Program запрашивает номер телефона - перехватываем encryptedData и iv. Сравниваем IV между сессиями: статичный IV или корреляция с session_key указывает на криптографический дефект.
Ограничения инструментария: WeChat DevTools позволяет запускать Mini-Program в режиме отладки, но не эмулирует полный OBA-flow (нет реального wx.login()). Для полноценного тестирования нужно реальное устройство с установленным WeChat. Burp Suite Community Edition не поддерживает кастомные extensions для декодирования WeChat-специфичных payload - Professional версия обязательна для серьёзного аудита.

Чеклист безопасности OBA для разработчика и аудитора​

Нумерованный список действий для разработчика Mini-Program, аудитора или пентестера - в формате, пригодном для включения в отчёт:
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

1 834 уязвимых Mini-Program из ~47 000 проанализированных - около 4%. Звучит терпимо, пока не вспомнить, что WeChat хостит, по разным оценкам, несколько миллионов Mini-Programs. Экстраполяция грубая, но порядок понятен: десятки тысяч приложений с дефектами аутентификации, обрабатывающих платежи, медицинские данные и государственные сервисы.

Корневая причина не в сложности протокола - WeChat OBA проще стандартного OAuth 2.0. Причина в том, что среда суперприложений создала ситуацию, где разработчик доставки еды реализует криптографическую привязку сессии к session_key. Это не его компетенция, и никакая документация это не исправит. Платформа должна брать безопасность аутентификации на себя - через server-side enforcement на уровне code2Session API, а не рекомендации в dev docs, которые большинство разработчиков не читают.

Второй неудобный факт: статический анализ для этого класса уязвимостей мёртв. MiniCAT показал, что динамический подход обнаруживает несопоставимо больше проблем, чем любой SAST. Если исследуете Mini-Programs - без настроенного mitmproxy и автоматизации перехвата вы пропустите подавляющее большинство находок. И это касается не только WeChat: Alipay, TikTok, Baidu - тот же архитектурный паттерн, те же ошибки. Рынок суперприложений растёт, а количество исследователей, разбирающихся в специфике их OBA-протоколов, можно пересчитать по пальцам одной руки. Если хочется разобрать OAuth-цепочку от утечки openid до полного account takeover на живом стенде - web-категория на HackerLab.pro (https://hackerlab.pro) для этого подходит.
 
Последнее редактирование модератором:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab