todo/VLESS-SOCKS5-vulnerability.md
loop-uh 737f065567 Вики переехала на wiki2.zapret.moe: домен заменён во всём хранилище
wiki.zapret.moe заблокирован в России, читатели до редиректа не доходят. Во всех заметках, плашках [!mirror], ссылках и скриптах домен заменён на wiki2.zapret.moe; в AGENTS.md записано правило — ссылаться только на wiki2. Скрипт статистики считает своими заходы с обоих доменов. Чужие незакоммиченные правки в nuc/ в коммит не попали — только замена домена.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:15:27 -04:00

460 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
description: "Уязвимость VLESS/xray/sing-box клиентов: SOCKS5 без пароля на localhost раскрывает IP VPN-сервера любому приложению. Список уязвимых клиентов и защита."
---
> [!mirror] Резервное зеркало
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/VLESS-SOCKS5-vulnerability](https://wiki2.zapret.moe/VLESS-SOCKS5-vulnerability)
# Критическая уязвимость VLESS-клиентов: неаутентифицированный SOCKS5 на localhost
**Дата публикации:** 7 апреля 2026
**Источник:** [runetfreedom — ntc.party](https://ntc.party/t/topic/), [Habr](https://habr.com/ru/articles/1020080/)
**POC:** [github.com/runetfreedom/per-app-split-bypass-poc](https://github.com/runetfreedom/per-app-split-bypass-poc)
**Severity:** Critical (массовая эксплуатация неизбежна)
---
## TL;DR
Все популярные VLESS/xray/sing-box клиенты создают на localhost SOCKS5-прокси **без аутентификации**. Любое приложение-шпион на устройстве может подключиться к нему напрямую (минуя VpnService и per-app split tunneling), отправить запрос через прокси и узнать **выходной IP VPN-сервера**. Android Private Spaces (Knox, Shelter, Island) **не защищают** — loopback-интерфейс общий. Минцифры РФ разослало методичку по обнаружению VPN, включая сканирование характерных портов.
---
## 1. Предпосылки
Минцифры РФ официально потребовало от аккредитованных российских IT-компаний внедрения шпионских модулей в свои продукты для обнаружения и блокировки персональных VPN. Выпущена подробная методичка, описывающая:
- Какие порты сканировать для обнаружения прокси
- Какие VPN-признаки искать (флаги, интерфейсы, паттерны трафика)
- Какую информацию собирать и передавать
**Характерные Proxy-порты из методички Минцифры:**
| Тип | Порты |
|-----|-------|
| SOCKS | 1080, 9000, 5555, 16000-16100 |
| HTTP | 80, 443, 3128, 3127, 8000, 8080, 8081, 8888 |
| Прозрачные Proxy | 80, 443, 4080, 7000/7044, 8082, 12345 |
| Tor | 9050, 9051, 9150 |
> Примечание: стандартные порты xray-клиентов (10808, 10809, 2080) в методичке пока не указаны, но скан всех портов localhost занимает секунды.
Яндекс **уже использовал** подобную технику ранее ([[Localhost-tracking-Meta-Yandex-SOCKS5|сканирование localhost для обнаружения прокси]]).
**Обновление (апрель 2026):** Зафиксированы случаи активного подавления VPN-соединений сервисами Яндекса. При работе Яндекс.Музыки на мобильном интернете VPN-соединение через NekoBox (sing-box) принудительно сбрасывается. Переход на другой VPN-клиент (Karing) решает проблему, что указывает на fingerprinting конкретных VPN-протоколов/клиентов на уровне DPI.
---
## 2. Архитектура VPN-клиентов на Android
### Нормальная цепочка прохождения трафика
![[wiki-anim-socks5-bypass.svg|Анимация: шпион обращается на localhost:10808 мимо VpnService]]
**VpnService** — системный механизм Android, перехватывающий весь сетевой трафик и перенаправляющий его в TUN-интерфейс. Через него реализуется per-app split tunneling — выбор, какие приложения идут через VPN.
### Ключевая деталь
SOCKS5-прокси xray/sing-box — это **отдельный TCP-сервер**, слушающий на `127.0.0.1:PORT`. Он доступен **любому процессу** на устройстве через loopback, **независимо от VpnService**.
---
## 3. Суть уязвимости
### Атака
![[wiki-anim-socks5-bypass.svg|Анимация: шпион обращается на localhost:10808 мимо VpnService]]
**Шаг 1.** Шпионский модуль сканирует порты localhost. Полный скан 65535 портов на loopback — **секунды**, нулевая нагрузка. Можно сканировать по триггеру (VPN-флаг системы).
**Шаг 2.** Найдя открытый SOCKS5 без аутентификации, шпион подключается и отправляет запрос на `ifconfig.me` (или аналог).
**Шаг 3.** Ответ содержит **выходной IP VPN-сервера**. IP передаётся в РКН → сервер блокируется.
### Почему не помогает per-app split tunneling
Split tunneling работает через VpnService, который управляет TUN-интерфейсом. Но прямое подключение к `127.0.0.1:10808` **не проходит через TUN** — это внутренний loopback, он не маршрутизируется через VPN.
### Почему не помогают приватные пространства (Knox/Shelter/Island)
Android Private Spaces изолируют:
- ✅ Файловую систему
- ✅ VpnService (отдельный VPN-профиль)
- ❌ **Loopback-интерфейс НЕ изолирован**
Процесс из Knox/Shelter **видит** `127.0.0.1:10808` основного профиля. Это создаёт **ложное чувство безопасности**.
### Почему смена порта не помогает
> «Достаточно заменить порты на рандомные» — нет.
Скан портов на localhost занимает секунды. Шпиону не нужно знать порт заранее — он проверит все открытые порты и попробует SOCKS5 handshake на каждом.
### Метод /proc/net/route: IP VPN-сервера раскрыт через таблицу маршрутизации
Помимо сканирования портов, существует ещё более простой метод обнаружения IP VPN-сервера:
Когда VPN активен, Android создаёт **host route** (маска /32 = `255.255.255.255`) для IP VPN-сервера через **реальный сетевой интерфейс** (wlan0/rmnet0), минуя TUN-интерфейс VPN. Это необходимо, чтобы пакеты VPN-туннеля доходили до сервера через физическую сеть.
```
$ cat /proc/net/route
Iface Destination Gateway Flags Mask
tun0 00000000 00000000 ... 00000000 ← default через VPN
wlan0 B9A5C041 0201A8C0 ... FFFFFFFF ← host route к 65.197.165.185 через WiFi
```
**Любое приложение может прочитать `/proc/net/route` без root.**
Это раскрывает IP VPN-сервера для **ВСЕХ типов VPN**:
- WireGuard / Amnezia VPN (UDP)
- OpenVPN (TCP/UDP)
- xray / VLESS / Trojan (TCP)
- IPSec / IKEv2
**Работает даже при раздельном туннелировании** — маршрут к серверу всегда проходит через реальный интерфейс, иначе VPN-туннель не смог бы функционировать.
Вместе с `/proc/net/udp` и `/proc/net/tcp` (которые показывают ESTABLISHED-соединения всех приложений) шпион получает:
- IP и порт VPN-сервера
- UID приложения-владельца (→ имя пакета через `PackageManager.getPackagesForUid()`)
- Протокол (TCP/UDP → угадать тип VPN: UDP:51820 = WireGuard, TCP:443 = VLESS)
---
## 4. Happ: отдельная категория опасности
Клиент Happ (iOS) помимо уязвимого SOCKS5 включает **xray gRPC API с HandlerService БЕЗ аутентификации**.
### Что такое xray API
xray-core поддерживает gRPC API с несколькими сервисами:
| Сервис | Назначение | Опасность |
|--------|-----------|-----------|
| **StatsService** | Статистика трафика, онлайн-пользователи | Низкая |
| **LoggerService** | Управление логированием | Низкая |
| **HandlerService** | Управление inbound/outbound, добавление/удаление пользователей, **дамп конфигурации** | 🔴 **КРИТИЧЕСКАЯ** |
| **RoutingService** | Управление правилами маршрутизации | Средняя |
| **ReflectionService** | Список доступных API-методов | Средняя |
### Что позволяет HandlerService
- Дампить **полные конфиги outbound** (включая ключи шифрования, IP сервера, SNI)
- Добавлять/удалять inbound и outbound
- Управлять пользователями протоколов (VMess, VLESS, Trojan, Shadowsocks)
- Получать список всех inbound/outbound
### Цепочка атаки на пользователей Happ
![[wiki-anim-grpc-chain.svg|Схема: цепочка атаки через открытый gRPC API прокси-ядра]]
### Позиция разработчиков Happ
Заявили, что API нужен для «сбора статистики подключения». Это **ложь** — для статистики достаточно `LogService` или `StatsService`. HandlerService предоставляет полный контроль над конфигурацией.
Реверс-инжиниринг показал: при смене конфига Happ **перезапускает xray целиком**, а не использует HandlerService для hot-swap. Легитимного применения HandlerService не найдено.
### Рекомендация
- **Немедленно прекратить использование Happ**
- Заблокировать Happ на серверах подписок по UserAgent: `Happ/*`
- Один пользователь с Happ компрометирует **весь сервер** (включая входной IP и SNI)
> [!warning] Открытый API убран, но не единственная претензия к Happ
> Проверка по коду приложения ([[xray/happ-problems|подробный разбор]]) показывает: служба `HandlerService` была в Happ для Android 3.16.1 от 1 апреля 2026 года и исчезла уже в 3.16.2 от 7 апреля — в день публикации этого разбора на Хабре. Рекомендация «немедленно удалить» держалась на утверждении, что исправить проблему невозможно, а это не подтвердилось. При этом закрытый код, телеметрия на собственные домены Happ и SOCKS5 без пароля по умолчанию остаются актуальными претензиями на 18 октября 2026 года.
### Подписочная система НЕ защищает
Распространённое заблуждение: «мой сервер на подписке, его не найдут». Это не так.
Через xray gRPC API (HandlerService) любое приложение на устройстве получает **полную конфигурацию VPN-подключения**:
| Поле | Пример | Что это даёт шпиону |
|------|--------|---------------------|
| `protocolName` | splithttp | Протокол транспорта |
| `address:port` | server.amazonaws.com:443 | **Адрес сервера → заблокировать** |
| `uuid` | f7fd6ed1-8cbb-... | **UUID → клонировать подключение** |
| `reality sni` | checkip.amazonaws.com | SNI → идентификация |
| `reality publicKey` | qTdiDYiav3Rtv0kw... | **Публичный ключ** |
**Подписка = сервер + UUID + ключи. Всё это хранится в xray-core и отдаётся через gRPC API без пароля.** Любое приложение может прочитать вашу платную подписку целиком и передать данные для блокировки.
Доказательство: приложение [per-app-split-bypass-poc](https://github.com/runetfreedom/per-app-split-bypass-poc) демонстрирует полный дамп конфигурации через xray API на Android.
---
## 5. Техническая документация: аутентификация SOCKS5
### xray-core: конфигурация SOCKS5 inbound
#### Без аутентификации (уязвимая конфигурация)
```json
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
```
#### С аутентификацией (безопасная конфигурация)
```json
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "password",
"accounts": [
{
"user": "randomUser_a8f3b2",
"pass": "randomPass_7c4e91d0"
}
],
"udp": false
}
}
```
**Поля:**
| Поле | Тип | Значение |
|------|-----|----------|
| `auth` | `"noauth"` / `"password"` | Режим аутентификации. По умолчанию `"noauth"` |
| `accounts` | `[{user, pass}]` | Массив учётных записей. Работает только при `auth: "password"` |
| `udp` | `boolean` | Включение UDP. **Важно:** UDP в SOCKS5 фактически работает без авторизации |
| `ip` | `string` | Локальный IP для UDP-соединений |
| `userLevel` | `number` | Уровень пользователя для политик |
> ⚠️ **SOCKS5 UDP проблема:** протокол SOCKS5 аутентифицирует только TCP-соединение. UDP ASSOCIATE команда привязывает UDP-порт, но сами UDP-пакеты **не проходят повторную аутентификацию**. Для полной защиты UDP нужно отключать.
### sing-box: конфигурация SOCKS/mixed inbound
#### Без аутентификации (уязвимая конфигурация)
```json
{
"type": "mixed",
"tag": "mixed-in",
"listen": "0.0.0.0",
"listen_port": 2080
}
```
#### С аутентификацией (безопасная конфигурация)
```json
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 2080,
"users": [
{
"username": "randomUser_d4c1a7",
"password": "randomPass_9e2f5b83"
}
]
}
```
**Поля:**
| Поле | Тип | Значение |
|------|-----|----------|
| `type` | `"socks"` / `"mixed"` | `mixed` поддерживает SOCKS4/4a/5 и HTTP |
| `users` | `[{username, password}]` | Массив учётных записей. Без этого поля — без аутентификации |
| `listen` | `string` | Адрес прослушивания |
| `listen_port` | `number` | Порт |
| `set_system_proxy` | `boolean` | Автоматическая настройка системного прокси (Linux/Android/Windows/macOS) |
> Примечание: sing-box **не создаёт mixed inbound автоматически** — это делают клиенты и генераторы конфигов. Позиция разработчика sing-box: это «skill issue» клиентов.
---
## 6. Статус проверенных клиентов
Уведомление разработчикам разослано **10 марта 2026**. Статус на 7 апреля 2026:
| Клиент | Платформа | Ядро | SOCKS5 auth | Статус | Примечание |
|--------|-----------|------|-------------|--------|------------|
| **Happ** | iOS | xray | ❌ Нет | 🔴 **Особо опасен** | API HandlerService без авторизации, дамп конфигов |
| **v2RayTun** | Android | xray | ❌ Нет | 🟡 Уязвим | Разработчик поблагодарил, обещал исправить |
| **V2BOX** | iOS/Android | xray | ❌ Нет | 🟡 Уязвим | |
| **v2rayNG** | Android | xray | ❌ Нет | 🟡 Уязвим | Порт 10808 по умолчанию |
| **Hiddify** | Android/iOS | sing-box | ❌ Нет | 🟡 Уязвим | |
| **Exclave** | iOS | xray | ❌ Нет | 🟡 Уязвим | |
| **Npv Tunnel** | Android | xray | ❌ Нет | 🟡 Уязвим | |
| **Neko Box** | Android | sing-box | ❌ Нет | 🟡 Уязвим | Порт 2080 по умолчанию |
| **Karing** | Android/iOS | sing-box | ❌ Нет | 🟡 Уязвим | Порты 3065-3067, можно добавить auth вручную |
| **v2rayN** | Windows | xray | ❌ Нет | 🟡 Уязвим | Можно менять порт, но не добавить auth |
| **Husi** | Android | sing-box | ✅ Есть | 🟢 Можно настроить | Login/pass на SOCKS |
| **SFA (sing-box for Android)** | Android | sing-box | ✅ Есть | 🟢 Можно настроить | Ручная настройка JSON |
| **Xray (saeeddev94)** | Android | xray | ✅ Есть | 🟢 Можно настроить | F-Droid, ручной JSON конфиг |
---
## 7. Статус XrayFluent (наш клиент)
### Текущая конфигурация
**Файл:** `xray_fluent/engines/xray/config_builder.py`, строки 191-206
```python
{
"tag": "socks-in",
"listen": PROXY_HOST, # 127.0.0.1
"port": int(socks_port), # 10808
"protocol": "socks",
"settings": {
"auth": "noauth", # ❌ БЕЗ АУТЕНТИФИКАЦИИ
"udp": True, # ⚠️ UDP включён
},
"sniffing": {
"enabled": True,
"destOverride": ["http", "tls", "quic"],
"routeOnly": True,
},
}
```
**Константы** (`xray_fluent/constants.py`):
- `PROXY_HOST = "127.0.0.1"` — только localhost ✅
- `DEFAULT_SOCKS_PORT = 10808` — стандартный порт ⚠️
- `DEFAULT_HTTP_PORT = 10809` — HTTP тоже без auth ⚠️
- `DEFAULT_XRAY_STATS_API_PORT = 19085` — API порт ⚠️
**Шаблоны** (`data/templates/xray/default.json`):
- Слушают на `0.0.0.0` — **хуже рантайма**, доступны из сети ❌
### Смягчающие факторы
XrayFluent — **десктопный Windows-клиент**, поэтому:
1. Windows Firewall может блокировать доступ к localhost из других приложений (но не по умолчанию для loopback)
2. xray routing rules с `process name` позволяют ограничить доступ
3. Нет VpnService-подобного механизма — атака через loopback менее вероятна
### Что нужно исправить
1. Добавить `"auth": "password"` с рандомными credentials (генерировать при каждом запуске)
2. Отключить UDP или реализовать UDP auth
3. Исправить шаблоны: заменить `0.0.0.0` на `127.0.0.1`
4. Проверить, какие API-сервисы включены (не должно быть HandlerService)
5. Добавить настройку в UI для включения/отключения SOCKS5 auth
---
## 8. [[VLESS-localhost-protection-guide|Защитные меры]]
### Для пользователей (клиентская сторона)
**На Android:**
1. Использовать клиенты с поддержкой SOCKS5 auth (Husi, SFA, saeeddev94/xray)
2. Если root: блокировать доступ к localhost через iptables для недоверенных приложений
3. **Немедленно удалить Happ** и заблокировать на серверах подписок
4. Держать российское ПО на **отдельном устройстве**
5. Не полагаться на Knox/Shelter/Island — loopback не изолирован
**На Windows:**
1. Настроить Windows Firewall для блокировки доступа к портам 10808/10809 для всех процессов кроме xray.exe и доверенных приложений
2. Использовать рандомные порты (не 10808)
3. В xray routing rules добавить `process name` для разрешённых приложений
**На iOS:**
1. Ситуация сложная — большинство клиентов удалено из App Store и не получит обновлений
2. Единственный вариант — клиенты с возможностью ручной настройки JSON (если доступны)
### Для администраторов серверов
1. **Раздельные входной/выходной IP** — если утёк выходной, входной продолжает работать
2. **CloudFlare WARP на выходе** — как альтернатива второму IP: `xray → WARP → интернет`
3. **geoip:ru → block на сервере** — заблокировать исходящий трафик на российские IP, чтобы шпионы не могли связать паттерн трафика с подключением
4. **Блокировка Happ по UserAgent**: `Happ/*` на серверах подписок
5. **Мониторинг** — отслеживать нетипичные запросы (ifconfig.me, ipinfo.io и аналоги) через прокси
### Для разработчиков клиентов
1. **SOCKS5 auth по умолчанию** — генерировать рандомные credentials при каждом запуске
2. **Отключить UDP** в SOCKS5 или реализовать UDP-level auth
3. **Не включать xray API HandlerService** — для статистики достаточно StatsService/LogService
4. **Не слушать на 0.0.0.0** — только 127.0.0.1
5. **Рандомизировать порт** — не использовать стандартные 10808/2080/1080
### Маршрутизация (клиентская сторона)
Рекомендуемая стратегия на клиенте:
| Правило | Действие |
|:--|:--|
| `geoip:ru` | direct: российские IP напрямую |
| `geoip:private` | direct: локальные сети |
| остальное | proxy: через VPN |
На сервере:
| Правило | Действие |
|:--|:--|
| `geoip:ru` | block: запретить выход на российские IP |
| остальное | freedom: разрешить |
> В v2rayN для Windows эта стратегия уже реализована как пресет «Все, кроме РФ».
---
## 9. Технические детали: xray API (для понимания угрозы Happ)
### Формат конфигурации API
```json
{
"api": {
"tag": "api",
"services": [
"HandlerService",
"LoggerService",
"StatsService",
"RoutingService"
]
}
}
```
### gRPC методы HandlerService
| Метод | Описание | Опасность |
|-------|----------|-----------|
| `AddInbound` | Добавить новый inbound | Высокая |
| `RemoveInbound` | Удалить inbound | Высокая |
| `AlterInbound` | Изменить inbound | Высокая |
| `AddOutbound` | Добавить outbound | Высокая |
| `RemoveOutbound` | Удалить outbound | Высокая |
| `AlterOutbound` | Изменить outbound | Высокая |
| `GetInboundUsers` | Получить список пользователей inbound | Критическая |
| `GetInboundUsersCount` | Количество пользователей | Низкая |
### Как это эксплуатируется
1. Шпион находит gRPC API на localhost (скан портов)
2. Вызывает ReflectionService для получения списка методов
3. Через HandlerService дампит outbound — получает ключ, IP, SNI
4. В сочетании с уязвимостью конфигурации xray → **расшифровка трафика**
> О второй уязвимости автор намеренно не раскрывает деталей.
---
## 10. Источники
- [Статья на ntc.party](https://ntc.party/) — оригинальная публикация runetfreedom
- [Habr: Критическая уязвимость VLESS клиентов](https://habr.com/ru/articles/1020080/)
- [POC: per-app-split-bypass](https://github.com/runetfreedom/per-app-split-bypass-poc)
- [xray-core SOCKS inbound docs](https://xtls.github.io/en/config/inbounds/socks.html)
- [xray-core API docs](https://xtls.github.io/en/config/api.html)
- [sing-box SOCKS inbound docs](https://sing-box.sagernet.org/configuration/inbound/socks/)
- [sing-box Mixed inbound docs](https://sing-box.sagernet.org/configuration/inbound/mixed/)
- [XTLS BBS: Malicious Activity of Closed-Source Xray Clients](https://github.com/XTLS/BBS/issues/8)
- [Meduza: Минцифры разослало методичку по VPN](https://meduza.io/news/2026/04/06/mintsifry-razoslalo-rossiyskim-kompaniyam-metodichku-po-poisku-vpn-na-ustroystvah-polzovateley)