Введение: WebSocket в современном вебе
WebSocket — это протокол связи, обеспечивающий канал двусторонней передачи данных поверх одного соединения TCP.Протокол WS: handshake, frames, opcodes
Клиент отправляет HTTP-запрос (метод GET), и в случае успеха сервер возвращает HTTP-ответ с кодом состояния 101 (Switching Protocols), что говорит о том, что сервер принял запрос на переход с HTTP на постоянный протокол WS. Клиенты HTTP и WebSocket могут подключаться к серверу через один и тот же порт, поскольку процедура установления соединения (handshake) использует протокол HTTP.После завершения процедуры рукопожатия клиент и сервер могут в любой момент обмениваться сообщениями с данными (текстовыми или бинарными) и управляющими сообщениями (Close, Ping, Pong). Сообщение состоит из одного кадра, если оно не фрагментировано, или как минимум из двух кадров, если оно фрагментировано.
Фрагментация разбивает сообщение на два или более кадров. Она позволяет отправлять сообщения, когда начальные данные уже доступны, но их полная длина еще неизвестна. Без фрагментации всё сообщение должно передаваться в одном кадре, поэтому для отправки даже первого байта необходимо знать полную длину данных, что требует использования буфера.
Чтобы получатель понимал, какого типа данные к нему пришли и что с ними делать, в начале каждого фрейма отправляется специальный маркер – Opcode.
Opcode занимает 4 бита в заголовке фрейма. Это значит, что теоретически возможных кодов может быть 16 и RFC 6455 делит их на 3 категории: тестовые/бинарные данные, служебные команды и зарезервированные коды.
WebSocket vs HTTP: модель безопасности
Каждый HTTP запрос изолирован (если не рассматривать сессии на уровне приложения). Аутентификация происходит через заголовки, куки или TLS-сертификаты.WebSocket не имеет собственного встроенного механизма аутентификации, "аутентификация" происходит именно в рамках WebSocket handshake, который является HTTP-запросом (с заголовками Upgrade: websocket, Sec-WebSocket-Key и т.д.). После того как Handshake завершён, заголовки больше не передаются. Если хакер сможет перехватить или подменить TCP соединение, он получит полный доступ без необходимости повторно аутентифицироваться.
Разницы между протоколами нет, оба используют TLS. Использовать незащищённый ws:// – огромный риск. Мало того, что трафик открыт, так ещё и промежуточные прокси-серверы часто не понимают чистый WebSocket на 80 порту и просто обрывают соединение. wss:// решает проблему, упаковывая фреймы в TLS.
В случае HTTP - Браузеры жёстко принимают правила SOP и CORS. Скрипт с левого сайта не может просто так прочитать данные из API банка, если банк явно не разрешил это через заголовки CORS.
В случае WebSocket – он вообще не подчиняется SOP. Браузер позволит скрипту с любого сайта открыть WebSocket-соединение к любому серверу. Вместо блокировки браузер делает следующее: При Handshake он честно добавляет заголовк Origin, и если сервер видит не доверенный источник, сбрасывает подключение. Если разработчик забыл проверить Origin, возникает атака CSWSH – аналог SSRF, но для веб-сектов.
WebSocket имеет особенность. Все фреймы, отправляемые от клиента к серверу, в обязательном порядке должны быть замаскированы (т.е побитовая XOR-операция данных фрейма с 32-битным случайным ключём, который генерируется клиентом для каждого фрейма). Фреймы от сервера к клиенту не маскируются. Это защита от «глупых» или плохо настроенных прокси-серверов. Если клиент отправит предсказуемый HTTP-подобный запрос через WebSocket без маски, то прокси-сервер может перепутать его с обычным HTTP-запросом, закэшировать ответ от сервера и затем отдавать этот кэш другим пользователям, что приведёт к отравлению кэша.
Разведка
В отличие от HTTP, где все эндпоиты видны в документации или легко перебираются, WebSocket-соединения часто «прячутся» за дефолтными портами и специфическими путями.
Обнаружение WebSocket endpoints
Самый надёжный способ – изучить фронтенд приложения, так как именно браузер клиента должен знать, куда и как подключаться.Нужно искать следы инициализации в JS:
- Обычные конструкторы:
new WebSocket (,WebSocket( - Ищите схемы протоколов в строках:
ws://иwss:// - Ищем ключевые слова популярных библиотек:
io(,SockJS,HubConnectionBuilder,$ActionCable
Чтобы утилита поняла, что мы ищем именно WS, в каждом запросе при переборе путей обязательно указываем заголовки обновления протоколов.
Иногда архитектура сокетов раскрывается через сопутствующие файлы или ошибки конфигурации.
Для автоматизации процесса обнаружения можно использовать специализированный софт:
Websocat или wscat: CLI тулзы для быстрой проверки. Можем написать bash скрипт, который перебирает URL и пытается установить соединение:
Bash:
websocat –t {URL}
Или с помощью расширения для Burp Suite – WebSocket Smuggler.
Анализ сообщений и протоколов
На данном этапе стоит задача понять, как приложение общается через этот открытый канал, какую структуру имеют данные и какие логические уязвимости могут в них скрываться. Т.к WebSocket – это лишь транспорт, внутри него может быть "развёрнут" абсолютно любой протокол.Первое, что нужно посмотреть это тип отправляемых файлов во вкладке Network (DevTools).
Если приложение использует Binary frames, вам придётся выяснить, как их декодировать. Популярный бинарный формат – Protobuf (Google Protocol Buffers).
MessagePack / BSON – бинарные аналоги JSON.
Проблемы аутентификации
Протокол WebSocket не имеет встроенных механизмов аутентификации. Это полностью задача разработчика.Аутентификация по рукопожатию
Самая тривиальная ошибка – когда WebSocket вообще не проверяет, кто подключается.Ни кук, ни токенов, просто заголовок Upgrade: websocket. Злоумышленник может подключиться к сокету напрямую и начать слушать чужие сообщения, либо отправлять команды в систему от анона, если бэкенд не ограничил права.
Недостатки проверки токенов
Сервер верит токену, не проверяя его. А если разработчик использует JWT? Его можно декодировать и поменять на свой. Также сервер может вообще не смотреть на дату токена и принять «просроченный». Либо можно поменять алгоритм с RS256 на HS256, подписать токен известным ключём, и бэкенд запутается.Сохранение сессии через WS
Это такая атака, где атакующий заставялет жертву использовать известное ему сокет-соединение или конкретный идентификатор сессии, чтобы потом перехватить доступ к аккаунту после того, как жертва авторизуется.Аутентификация для каждого сообщения
Более продвинутый паттерн проектирования безопасности WebSocket, при котором проверка прав и подлинности пользователя происходит не один раз, а для каждого отправляемого фрейма с бизнес-логикой.Обход аутентификации
Момент когда злоумышленник получил доступ к данным или совершает действия, на которые у его учётной записи нет прав. Разработчики думают, что если этап HTTP Handshake прошёл успешно, то весь последующий внутри этого TCP-канала по дефолту безопасен и доверен, но это не так.
Контроль канала доступа
Механизм, определяющий, имеет ли право конкретное подключение подписываться на определённый канал/топик и отправлять туда сообщения.Ошибка разработчиков – открывать доступ к каналу только на основе имени, которое спрашивает клиент. Сервер считает, что если имя канала содержит UUID, то угадать его невозможно, следовательно, проверка прав не обязательна.
Каналы создаются для того, чтобы пользователи могли слушать обновления, но отправлять туда сообщения должен только сервер или администратор. Если права на канал настроены по принципу "всё или ничего", пользователь, подписавшийся на публичный канал, может обнаружить, что бэкенд принимает от него фреймы публикации в этот же канал.
IDOR через WebSocket IDs
Такая проблема возникает, когда бэкенд выполняет действие или возвращает конфиденциальные данные, слепо доверяя идентификаторам ресурсов, которые клиент присылает внеутри текстовых или бинарных фреймов, вместо того чтобы проверять права сессии.Если приложение использует обычные порядковые номера, то мы просто меняем число и получаем успешную эксплуатацию.
Атаки инъекцией
Инъекции в WebSocket работают также как и в классическом веб-приложении: сервер слепо доверяет входным данным и выполняет их как код.
XSS через WS сообщения
Вредоносный код JS передаётся внутри WebSocket-фреймов и выполняется в браузере жертвы.В стандартных веб-приложениях для распространения Stored XSS нужно, чтобы жертва зашла на определённую страницу, куда из базы подгрузится скрипт. В WebSocket-архитектуре всё происходит "на лету" благодаря модели Pub/Sub (Publish/Subscribe) или механизм бродкаста.
SQLi в WebSocket параметры
Да, казалось, что SQL injection бывает только в HTTP запросах, но нет.Хоть математика и синтаксис инъекций остаются стандартными, процесс тестирования и эксплуатации имеет уникальные ньюансы.
Большинство WAF инспектируют только фазу HTTP handshake. После того как соединение установлено, весь последующий трафик инкапсулируется во фреймы WebSocket и часто идет внутри TLS-шифрования.
Command injection
Уязвимость критического уровня, т.к даёт RCE. Редкая находка для стандартных веб-приложений, но она регулярно встречается в специализированных экосистемах, использующих real-time протоколы.CSWSH
CSWSH или же Cross-Site WebSocket Hijacking – это аналог CSRF-атаки для вебсокетов.
Механика Cross-Site WebSocket Hijacking
Атака основана на свойстве браузеров и особенностях спецификации протокола. Жертва авторизуется на легитимный и уязвимый сайт, вводит логин/пароль. Сервер успешно авторизует его и устанавливает сессионную куку.Не закрывая вкладку, пользователь переходит на сайт хакера.
В JS страницы зашит скрипт, который срабатывает автоматически при загрузке. Он пытается установить WebSocket-соединение с бэкендом сайта.
Классическая политика единого источника SOP запретила бы скрипту с плохого сайта читать ответы от легитимного. НО на WebSocket SOP не распространяется. Браузер успешно формирует стандартный HTTP-запрос Upgrade к легитимному сайту и делает 2 вещи:
- Автоматически прикрепляет сессионные куки легитимного сайта, так как запрос идёт к этому домену.
- Заполняет заголовок Origin, указывая, откуда пришёл запрос.
PoC и эксплуатация
Для написания PoC (Proof-of-Concept) нам нужно 3 вещи:- WebSocket URL: Точный адрес эндпоинта
- Тип аутентификации: Если приложение использует Cookie для авторизации handshake
- Формат стартовых сообщений: Если сервер требует от клиента отправки какого-то JSON сразу после подключения, скопируйте его.
- Запустите локальный сервер с помощью с кодом, который и выполнит взаимодействие
- Симулируйте жертву: В браузере откройте вкладку и перейдите на локальный python севрер
- Проанализируйте вывод
Инструментарий
Для успешного теста на проникновения WebSocket нам понадобится документация Burp Suite: WebSocket testing, а также утилиты для работы с WebSocket о которых мы уже говорили.Burp Suite: WebSocket testing
Тестирование WebSocket в Burp Suite делится на 2 фазы: атака на фазу рукопожатий и манипуляция внутренними фреймами данных.- Перехват и анализ фреймов (WebSocket History)
- Модификация на лету (Proxy Intercept)
- Работа в Burp с запросами (Repeater)
- Тестирование уязвимости handshake (CSWSH)
wscat и websocat
Wscat – это простая и легковесная утилита, написанная на Node.js. Она идеально подходит для быстрой работы в режиме "команда - ответ".
Bash:
wscat -c wss://check.com/ws -H "Authorization: xxx" -H "Cookie: session=xxx"
Websocat – это гораздо более мощный, гибкий и быстрый инструмент, написанный на Rust. Он умеет связывать WebSocket со стандартным вводом/выводом, файлами, TCP-сокетами, UDP, UNIX-сокетами и запускать процессы ОС для обработки входящего трафика.
Bash:
websocat -t wss://echo.check.com
Тестирование, специфичное для конкретной платформы
Это подход в пентесте WebSocket, ориентированный на анализ конкретных высокоуровневых библиотек. Большинство веб-приложений построено на базе абстракций вроде Socket.io или SignalR.Socket.IO
Это самый популярный JS-фреймворк для real-time обмена. Он работает поверх обёртки Engine.io, которая кодирует сообщения специальными числовыми префиксами.SignalR
Open-Source библиотека от Microsoft для разработчиков на платформе .NET, предназначенная для добавления real-time функционала в веб-приложения. Главное достояние SignalR – вам не нужно писать сложный код для низкоуровневых сокетов.Литература
https://en.wikipedia.org/wiki/WebSockethttps://iaraoz.medium.com/hacking-apis-exploiting-websockets-insecure-implementations-a69cba59b0ad – required registration
https://portswigger.net/web-security/websockets
https://portswigger.net/burp/documentation/desktop/testing-workflow/vulnerabilities/websockets
https://ably.com/blog/websocket-authentication
https://www.superdevacademy.com/en/blogs/access-control-websocket-chat
https://nhimg.org/glossary/websocket-command-injection/
https://github.com/websockets/wscat
https://github.com/vi/websocat
https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks
https://socket.io/
https://github.com/signalr/signalr
https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr