167 lines
11 KiB
Markdown
167 lines
11 KiB
Markdown
|
|
# 02. Threat model — Montana Android v6.5.0
|
|||
|
|
|
|||
|
|
## Атакующие — классификация
|
|||
|
|
|
|||
|
|
### A. Пассивный сетевой наблюдатель (DPI на ISP)
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Виден весь трафик клиента до публичного интернета
|
|||
|
|
- Может выполнять traffic analysis (timing, size patterns)
|
|||
|
|
- Не может выполнить активное соединение к клиенту извне (NAT)
|
|||
|
|
|
|||
|
|
**Защита:**
|
|||
|
|
- Reality protocol — handshake выглядит как обычный TLS-1.3 к `www.googletagmanager.com`. SNI Echo маскирует destination.
|
|||
|
|
- Pinned fingerprint Chrome 120+. JA3/JA4 хэши совпадают с реальным Chrome.
|
|||
|
|
|
|||
|
|
**Открыто:**
|
|||
|
|
- Timing-based traffic analysis (всплески запросов соответствуют WebRTC, видео, и т.п.)
|
|||
|
|
- Если DPI имеет ML-классификатор Reality (известно научное исследование GFW 2024) — обнаружение возможно
|
|||
|
|
|
|||
|
|
### B. Активный сетевой наблюдатель (active probing)
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Может выполнять TCP-зондирование `91.132.142.42:443` (Helsinki публичный IP)
|
|||
|
|
- Может сравнивать ответы с эталонными `www.googletagmanager.com:443`
|
|||
|
|
|
|||
|
|
**Защита:**
|
|||
|
|
- Reality terminate на правильный destination через **SNI Echo** — если клиент шлёт неправильный сертификат, xray прозрачно проксирует к real `googletagmanager.com:443`.
|
|||
|
|
- На случай proxy-fallback: nginx `:80` decoy → отдаёт `"It works!"` HTML.
|
|||
|
|
|
|||
|
|
**Открыто:**
|
|||
|
|
- Атакующий с full state inspection (видит timing handshake и сравнивает с эталонным DNS+TLS к googletagmanager) может различить.
|
|||
|
|
|
|||
|
|
### C. Malicious Android app на том же устройстве
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Своё data dir (изолировано Android sandbox)
|
|||
|
|
- Возможно `MANAGE_EXTERNAL_STORAGE` (Android 11+) — доступ к `/sdcard/`, не к нашим private data
|
|||
|
|
- На rooted устройстве — полный доступ к `/data/data/quest.montana.vpn/`
|
|||
|
|
|
|||
|
|
**Защита (если не root):**
|
|||
|
|
- Android sandbox 0700 на data dir
|
|||
|
|
- localStorage WebView хранится в `/data/data/quest.montana.vpn/app_webview/Default/Local Storage/` — недоступен другим приложениям
|
|||
|
|
|
|||
|
|
**Открыто (если root):**
|
|||
|
|
- Seed 24 слов читается прямо из localStorage — **plain text**, не шифрован
|
|||
|
|
- Atomic recovery — атакующий получает все деньги, владельцу остаётся ничего
|
|||
|
|
|
|||
|
|
**Severity:** **средний** (зависит от того, root ли у пользователя; на стоковом Android защищено sandbox).
|
|||
|
|
|
|||
|
|
### D. Forensic / физический доступ к устройству
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Полная image копия `/data/data/quest.montana.vpn/`
|
|||
|
|
- Анализ offline
|
|||
|
|
|
|||
|
|
**Защита сейчас:**
|
|||
|
|
- Никакой кроме Android FBE (File-Based Encryption) которое работает только при выключенном устройстве и неизвестном пароле user.
|
|||
|
|
|
|||
|
|
**Открыто:**
|
|||
|
|
- На разблокированном устройстве или с известным паролем — seed читается тривиально.
|
|||
|
|
|
|||
|
|
**Severity:** **высокий** для пользователей хранящих значительный баланс. Closure: шифрование seed через user passcode + PBKDF2 (см. `07` F-6).
|
|||
|
|
|
|||
|
|
### E. Атака на VPN-сеть Montana через публичный endpoint
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Может поднять Montana VPN клиент (открытый VLESS URL)
|
|||
|
|
- Может слать heartbeat-ы с любого 40-hex адреса
|
|||
|
|
|
|||
|
|
**Защита сейчас:**
|
|||
|
|
- Только проверка `request.remote_addr ∈ MONTANA_NODES` (helsinki/frankfurt/newyork). Атакующий должен сначала подключиться через VPN — это сделает любой.
|
|||
|
|
- Никакой подписи heartbeat **нет**.
|
|||
|
|
|
|||
|
|
**Открыто (блокер):**
|
|||
|
|
- Атакующий с одним VPN-подключением шлёт 10⁶ heartbeat от 10⁶ fake-адресов → 10³ Ɉ/сек на fake-баланс
|
|||
|
|
- Экономика начисления рушится
|
|||
|
|
|
|||
|
|
**Severity:** **блокер mainnet**. Closure: подпись Falcon-512 (см. `07` F-2, требует TimeChain integration M-VPN-2/3).
|
|||
|
|
|
|||
|
|
### F. Compromise CI/build pipeline
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Подмена `bip39-en.txt` в APK при сборке
|
|||
|
|
- Подмена UUID/Reality keys в Kotlin
|
|||
|
|
|
|||
|
|
**Защита сейчас:**
|
|||
|
|
- BIP39 wordlist: **hardcoded SHA-256** в `MainActivity.kt` — если подменили, `bip39()` возвращает пустую строку, app не работает
|
|||
|
|
- APK signature: Genesis-keystore, fingerprint известен и публичен
|
|||
|
|
- Reproducible builds — частично (см. `08-Воспроизводимая-сборка.md`)
|
|||
|
|
|
|||
|
|
**Открыто:**
|
|||
|
|
- Reality keys и UUID **захардкожены** в коде, не имеют integrity check — атакующий может подменить в скомпрометированной сборке без обнаружения
|
|||
|
|
- Closure: `[C-1]` SSOT — keys должны загружаться из одного authoritative источника с подписью (см. `07` CF-4).
|
|||
|
|
|
|||
|
|
### G. Mass surveillance government adversary
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Может координировать DPI с ML-классификатором
|
|||
|
|
- Может выпустить subpoena/court order на hosting provider узла Helsinki (Финляндия — нейтральная юрисдикция, но не безопасна абсолютно)
|
|||
|
|
- Может физически захватить узел (закон или операция)
|
|||
|
|
|
|||
|
|
**Защита:**
|
|||
|
|
- Юрисдикция Finland — нейтральная, без mass surveillance законов аналогичных Five Eyes
|
|||
|
|
- Каскад через два exit-узла (Frankfurt DE / NewYork US) — добавляет дополнительный hop
|
|||
|
|
- Reality маскировка — повышает порог obfuscation
|
|||
|
|
|
|||
|
|
**Открыто:**
|
|||
|
|
- Frankfurt (Germany) и NewYork (USA) — оба под юрисдикциями с MLAT-соглашениями
|
|||
|
|
- Если атакующий контролирует Helsinki + один из exit — может deanonymize пользователя
|
|||
|
|
- Compromise двух узлов из трёх → каскад теряет силу
|
|||
|
|
|
|||
|
|
**Severity:** государственный actor — out of MVP scope. Дополнительные меры (Tor onion routing, additional jurisdictions) — future work.
|
|||
|
|
|
|||
|
|
### H. Sybil-атаки
|
|||
|
|
|
|||
|
|
**Капабилитности:**
|
|||
|
|
- Создание миллиона BIP39-кошельков (бесплатно)
|
|||
|
|
- Отправка heartbeat с каждого через VPN
|
|||
|
|
|
|||
|
|
**Защита:**
|
|||
|
|
- См. атакующий **E** выше. Сейчас не защищено никак.
|
|||
|
|
|
|||
|
|
**Severity:** **блокер mainnet**. Closure: TimeChain validator state + Falcon signature per heartbeat (M-VPN-2/3).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Что приложение защищает
|
|||
|
|
|
|||
|
|
| Свойство | Защищено? | Механизм | Ограничения |
|
|||
|
|
|----------|-----------|----------|--------------|
|
|||
|
|
| Identity (seed) от других apps | **да** (если не root) | Android sandbox 0700 | Не защищено от root, forensic |
|
|||
|
|
| Identity от network adversary | **да** | Seed никогда не покидает устройство | n/a |
|
|||
|
|
| Identity от подмены в APK | **частично** | BIP39 wordlist SHA-256 check | Reality keys не verified |
|
|||
|
|
| Traffic content от пассивного DPI | **да** | Reality TLS-1.3 inside | Timing analysis возможен |
|
|||
|
|
| Traffic content от active probing | **да** | SNI Echo decoy | Full state inspection — открыто |
|
|||
|
|
| Целостность баланса | **нет** | n/a | Sybil-атака открыта (E,H блокеры) |
|
|||
|
|
| Authentication heartbeat | **нет** | n/a | Любой может слать heartbeat (E блокер) |
|
|||
|
|
| Persistence баланса при отказе сервера | **нет** | Single Moscow file | TimeChain integration отложена |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Предположения (assumptions)
|
|||
|
|
|
|||
|
|
1. **Android FBE работает корректно** — данные приложения зашифрованы при выключенном устройстве.
|
|||
|
|
2. **WebView SubtleCrypto детерминирован** — `crypto.subtle.digest('SHA-256', ...)` и `deriveBits('PBKDF2', ...)` дают идентичный результат на разных Chromium-версиях Android. (См. `06-Восстановление.md` — для верификации требуются tests on multiple Android versions.)
|
|||
|
|
3. **xray-core реализует Reality корректно** — внешний аудит xray не входит в наш scope. Версия v26.2.6 актуальна на 2026-05.
|
|||
|
|
4. **haproxy stick-table персистентна 24h** — verified empirically (см. `04-Сетевой-слой.md`).
|
|||
|
|
5. **Genesis keystore хранится у автора в безопасном месте** — компрометация = возможность подписать malicious APK.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Запреты в коде (что архитектурно невозможно)
|
|||
|
|
|
|||
|
|
1. **Heartbeat не идёт мимо VPN** — `MontanaVpnService.sendHeartbeat()` всегда через `socksConnect(127.0.0.1:10808)` (SOCKS5 локального xray).
|
|||
|
|
2. **App не использует свой VPN для своего трафика** — `addDisallowedApplication(packageName)` исключает quest.montana.vpn из своего же TUN.
|
|||
|
|
3. **Версия не дублируется** — `versionCode` и `versionName` только в `build.gradle.kts`, нигде в коде явно.
|
|||
|
|
4. **xray access logs отключены** — `"access": "none"` в конфиге → logcat не спамит.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Outside scope этого аудита
|
|||
|
|
|
|||
|
|
- Уязвимости в Android OS (CVE на WebView, kernel etc.) — обязанность пользователя обновляться
|
|||
|
|
- Уязвимости в Linux kernel exit-нод — обязанность hosting provider
|
|||
|
|
- DDoS на публичный Helsinki:443 — на уровне hosting provider (THE.Hosting) + cloudflare если включено
|
|||
|
|
- Юридический аудит соответствия GDPR / законам о связи — отдельная экспертиза
|