# Критическая уязвимость 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

### Нормальная цепочка прохождения трафика

```
Приложение
    ↓
VpnService (Android системный API)
    ↓
tun2socks (TUN-интерфейс → SOCKS)
    ↓
xray/sing-box SOCKS5 (localhost:10808)
    ↓
VPN-сервер (VLESS/Trojan/SS)
    ↓
Интернет (freedom)
```

**VpnService** — системный механизм Android, перехватывающий весь сетевой трафик и перенаправляющий его в TUN-интерфейс. Через него реализуется per-app split tunneling — выбор, какие приложения идут через VPN.

### Ключевая деталь

SOCKS5-прокси xray/sing-box — это **отдельный TCP-сервер**, слушающий на `127.0.0.1:PORT`. Он доступен **любому процессу** на устройстве через loopback, **независимо от VpnService**.

---

## 3. Суть уязвимости

### Атака

```
┌─ Обычное приложение → VpnService → tun2socks ──┐
│                                                   ↓
│                                      xray SOCKS5 (:10808) → VPN-сервер → Интернет
│                                                   ↑
└─ Шпион (Яндекс/WB/Ozon/...) ─→ localhost:10808 ─┘
        (минуя VpnService, split tunneling не работает)
```

**Шаг 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

```
Шпион → скан портов → находит API (gRPC) → HandlerService
    → дамп outbound конфига → извлечение: ключ + IP сервера + SNI
    → [+ вторая уязвимость конфигурации] → расшифровка трафика
```

### Позиция разработчиков Happ

Заявили, что API нужен для «сбора статистики подключения». Это **ложь** — для статистики достаточно `LogService` или `StatsService`. HandlerService предоставляет полный контроль над конфигурацией.

Реверс-инжиниринг показал: при смене конфига Happ **перезапускает xray целиком**, а не использует HandlerService для hot-swap. Легитимного применения HandlerService не найдено.

### Рекомендация

- **Немедленно прекратить использование Happ**
- Заблокировать Happ на серверах подписок по UserAgent: `Happ/*`
- Один пользователь с Happ компрометирует **весь сервер** (включая входной IP и SNI)

### Подписочная система НЕ защищает

Распространённое заблуждение: «мой сервер на подписке, его не найдут». Это не так.

Через 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)
