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

27 KiB
Raw Permalink Blame History

description
Уязвимость VLESS/xray/sing-box клиентов: SOCKS5 без пароля на localhost раскрывает IP VPN-сервера любому приложению. Список уязвимых клиентов и защита.

[!mirror] Резервное зеркало Актуальная версия этой страницы — на основной вики: wiki2.zapret.moe/VLESS-SOCKS5-vulnerability

Критическая уязвимость VLESS-клиентов: неаутентифицированный SOCKS5 на localhost

Дата публикации: 7 апреля 2026
Источник: runetfreedom — ntc.party, Habr
POC: 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).

Обновление (апрель 2026): Зафиксированы случаи активного подавления VPN-соединений сервисами Яндекса. При работе Яндекс.Музыки на мобильном интернете VPN-соединение через NekoBox (sing-box) принудительно сбрасывается. Переход на другой VPN-клиент (Karing) решает проблему, что указывает на fingerprinting конкретных VPN-протоколов/клиентов на уровне DPI.


2. Архитектура VPN-клиентов на Android

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

!wiki-anim-socks5-bypass.svg

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

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

Позиция разработчиков 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 демонстрирует полный дамп конфигурации через xray API на Android.


5. Техническая документация: аутентификация SOCKS5

xray-core: конфигурация SOCKS5 inbound

Без аутентификации (уязвимая конфигурация)

{
    "tag": "socks-in",
    "listen": "127.0.0.1",
    "port": 10808,
    "protocol": "socks",
    "settings": {
        "auth": "noauth",
        "udp": true
    }
}

С аутентификацией (безопасная конфигурация)

{
    "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

Без аутентификации (уязвимая конфигурация)

{
    "type": "mixed",
    "tag": "mixed-in",
    "listen": "0.0.0.0",
    "listen_port": 2080
}

С аутентификацией (безопасная конфигурация)

{
    "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

{
    "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

{
    "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. Источники