Некоторые аспекты позитивной и негативной моделей платформы «Вебмониторэкс»

Каждый новый специалист нашей практики Защиты приложений проходит нечто среднее между посвящением и стажировкой. Обычно в рамках задачи нужно развернуть уязвимое приложение, WAF одного из наших фокусных партнеров, а потом найти конкретную уязвимость, проэксплуатировать ее, посмотреть что видно на WAF в режиме мониторинга, а затем настроить WAF, чтобы он начал обнаруживать и блокировать данную уязвимость. Конечно, уязвимости при этом выбираются не такие, чтобы сразу по сигнатуре можно было бы ее обнаружить.

В этой статье младший системный инженер «К2 Кибербезопасность» Даниил Золотарев поделится задачей, которая выпала ему.

В ходе работы Даниилу пришлось защищать Juice Shop средствами платформы «Вебмониторэкс» и столкнуться с некоторыми аспектами негативной и позитивной моделей данного WAF. Далее мы рассмотрим примеры создания пользовательских правил, для блокировки атак Improper Input Validation (Неправильная проверка ввода). Таким образом наглядно продемонстрируем одну из ключевых возможностей WAF — закрытие дыр приложения в проде до фикса.

Рисунок 1 - Домашняя страница Juice Shop

Рисунок 1 — Домашняя страница Juice Shop

Juice Shop в качестве уязвимого приложения

В качестве уязвимого веб-приложения было выбрано довольно популярная разработка от сообщества OWASP — Juice Shop. Она представляет из себя веб-приложение — интернет-магазин по продаже соков. Но с одной ключевой особенностью — в нем спрятаны известные уязвимости из списка OWASP.  Поэтому это идеальный кандидат, чтобы проверить некоторые функции.

Мы разворачивали приложение и WAF на отдельных серверах в нашем Облаке, чтобы сымитировать реальные кейсы внедрения СЗИ. Juice Shop написан на Node.js, Express и Angular. Его можно развернуть в Docker, Vagrant, популярных облачных провайдерах и Node.js c утилитой npm. Так был выбран последний вариант. Все просто — команды с комментариями дальше в листинге:

sudo apt update
# Установка Node.js
sudo apt install nodejs
sudo apt install npm

# Клонируем репозиторий
git clone https://github.com/juice-shop/juice-shop.git --depth 1
cd juice-shop
# Устанавливаем Juice Shop
npm install

# Запускаем Juice Shop
npm start

С другими вариантами установки можно ознакомиться на Гитхабе Juice Shop — https://github.com/juice-shop/juice-shop .

После запуска проверяем в браузере. Приложение работает на 3000 порту. Прописываем в браузере https://localhost:3000, чтобы проверить работоспособность.

WAF Вебмониторэкс

Данный WAF устанавливается в нескольких вариантах, мы выбрали вариант on-prem lite, то есть фильтрующая нода устанавливается на виртуальный или физический сервер, а управления и сбор событий WAF происходит через API и Личный кабинет, которые располагаются на отдельных серверах с протекцией вендора. 

В нашем случае мы будем устанавливать фильтрующую ноду на сервер в нашем Облаке, так что получается серверная архитектура как на рисунке 2 ниже. Сервер с WAF будет работать как обратный прокси-сервер для приложения. Поэтому определяем ему внешний IP-адрес (Elastic IP), а оба сервера будут в одной локальной подсети уязвимого локального веб-приложения. Также мы настроили группы безопасности сетевых интерфейсов серверов, чтобы не было доступа из глобальной сети или сторонних подсетей. 

Рисунок 2 - Серверная архитектура, вид с облака

Рисунок 2 — Серверная архитектура, вид с облака

Платформу «Вебмониторэкс» можно развернуть на серверах с ОС Linux (Debian, Ubuntu, CentOS, AmazonLinux, AlmaLinux, Rocky Linux, Oracle Linux, SuSe Linux) на основе веб-сервера NGINX Stable и Plus, а также на платформе API-шлюза Kong. Помимо этого, реализована поддержка отечественных ОС: РЕД ОС, Альт Сервер 10 на основе веб-сервера Angie и Angie PRO.

Доступно развертывание на облачных платформах AWS, Google CP, Яндекс.Облако, Microsoft Azure, Alibaba Cloud и на частных облаках. В качестве инструментов развертывания выступают готовые образы платформ для первых двух вариантов, а также Docker образы NGINX, Kubernetes образы с Ingress-контролером или Sidecar-прокси NGINX и установочные пакеты DEB и RPM.

На нашем стенде мы разворачиваем фильтрующую ноду на сервере с ОС Linux Ubuntu 22.04 LTС в качестве модуля NGINX Stable 1.24. Установка ПО СЗИ приведена в листинге ниже.

# Установка Nginx stable и зависимостей
sudo apt install curl gnupg2 ca-certificates lsb-release
echo "deb http://nginx.org/packages/debian `lsb_release -cs` nginx"
sudo tee /etc/apt/sources.list.d/nginx.list
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
sudo apt update
sudo apt install nginx

# Добавление репозитория и установка пакетов платформы «Вебмониторэкс»
curl -fsSL https://repo.webmonitorx.ru/wmx.gpg | sudo apt-key add — 

sh -c "echo 'deb https://repo.webmonitorx.ru/ubuntu/webmonitorx-node jammy/4.6/' | sudo tee /etc/apt/sources.list.d/wmx.list" 

sudo apt update

sudo apt install --no-install-recommends wallarm-node nginx-module-wallarm

Далее редактируем конфигурацию NGINX следующим образом, добавляя выделенные строки. Логи устанавливаются в конфигурацию автоматически при установке пакетов платформы «Вебмониторэкс». Также мы установили TLS сертификаты Let`s Encrypt с помощью Certbot, подробнее можно почитать здесь — https://certbot.eff.org/ . Файл /etc/nginx/nginx.conf представлен ниже.

user www-data;

worker_processes auto;

worker_rlimit_nofile 2048;

load_module modules/ngx_http_wallarm_module.so;

pid /run/nginx.pid;

include /etc/nginx/modules-enabled/*.conf;

events {

         worker_connections 1024;

         multi_accept on;

}

http {

        include /etc/nginx/mime.types;

        default_type application/octet-stream;

        ##

        # SSL Settings

        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE

        ssl_prefer_server_ciphers on;

        ##

        # Logging Settings

        ##

        log_format wallarm_combined '$remote_addr - $remote_user [$time_local] '

                            '"$request" $request_id $status $body_bytes_sent '

                            '"$http_referer" "$http_user_agent" '

                            '$wallarm_request_cpu_time $wallarm_request_mono_time
                            $wallarm_serialized_size $wallarm_is_input_valid

                             $wallarm_attack_type $wallarm_attack_type_list';

        access_log /var/log/nginx/access.log;

        error_log /var/log/nginx/error.log;

        include /etc/nginx/conf.d/*.conf;

}

Теперь настраиваем обратный прокси-сервер в /etc/nginx/conf.d/default.conf (представлен в листинге ниже) с апстримом на наше уязвимое веб-приложение. И добавляем заголовки платформы «Вебмониторэкс»:

Первые два заголовка отвечают за режим работы WAF. По умолчанию у нас будет режим мониторинга, но второй заголовок говорит о том, что можно будет поменять на другие в личном кабинете. Третий заголовок отвечает за сущность, которая определяется в настройках в личном кабинете, для сбора и просмотра статистики только для конкретных приложений. Подробнее про заголовки можно прочитать в документации.

upstream vuln_app {

                server 172.31.85.6:3000;

        }

server{

        wallarm_mode_allow_override on;

        listen [::]:443 ssl ipv6only=on; # managed by Certbot

        listen 443 ssl; # managed by Certbot

        server_name juiceshop.k2.local;

        ssl_certificate /etc/letsencrypt/live/juiceshop.k2.local/cert.pem;

        ssl_certificate_key /etc/letsencrypt/live/ juiceshop.k2.local /privkey.pem;

        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

        location / {

                wallarm_mode monitoring;

                wallarm_application 1005;

                set_real_ip_from 172.31.85.11;

                real_ip_header X-Forwarded-For;

                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

                proxy_set_header Host $host;

                proxy_set_header X-Real-IP $remote_addr;

                proxy_pass http://vuln_app;

        }

}

server {

        if ($host = juiceshop.k2.local) {

                return 301 https://$host$request_uri;

        } # managed by Certbot

        listen 80 ;

        listen [::]:80 ;

        server_name juiceshop.k2.local;

        return 404; # managed by Certbot

}

В облачном личном кабинете создается новая нода — DEMO NODE (рисунок 3) и формируется токен для фильтрующего модуля. Командой sudo /usr/share/wallarm-common/register-node -t -H api.wallarm.ru токен регистрируется. После чего командами sudo service wallarm-tarantool restart и sudo service nginx restart перезапускаются сервисы NGINX и «Вебмониторэкс». В личном кабинете отображается белый IP-адрес. Для настроек на другие платформы обращайтесь к документации — https://docs.webmonitorx.ru/

Рисунок 3 - Личный кабинет

Рисунок 3 — Личный кабинет

После настройки приведу архитектуру нашего развернутого стенда для общего понимания на рисунке ниже.

Рисунок 4 - Архитектура стенда

Рисунок 4 — Архитектура стенда

Пользовательские правила на основе регулярных выражений и тестирование

В этом разделе создадим пользовательские правила для устранения некоторых уязвимостей в веб-приложении Juice Shop. В WAF от компании Вебмониторэкс расширенная функциональность работы с запросами.

Improper input validation (Неправильная проверка ввода)

Одной из главных возможностей WAF является предотвращение эксплуатации уязвимостей в стадии эксплуатации приложения до релиза с исправлением. Так частой ошибкой во время разработки веб-приложений является неправильная проверка ввода. UI предлагает выбор вариантов ввода, и разработчик не задумывается над тем, что данные ввода надо дополнительно парсить в бэкенде, потому что запрос может быть скомпрометирован. Яркий пример такого поведения — задача Zero Stars.

Zero Stars

Перейдем во вкладку «Отзыв пользователя» и заполним форму, выбрав 3 звезды. Затем перехватим сгенерированный запрос к серверу и изменим рейтинг на 0. Отправим запрос на сервер. Заметим, что запрос обработался сервером и успешно прошел валидацию.

578241350c89aa307eda7a87c3d64451.pngd98d692958f48cfca3b55bf78e798c65.pngeeced7d310dcf60bff05a7b3fb244bf5.png

Решение данной задачи с помощью платформы «Вебмониторэкс» состоит в создании пользовательского правила с обнаружением атаки на основе регулярного выражения. Создадим его в разделе «Rules», выберем «Создать индикатор атаки на основе регулярного выражения», выберем тип атаки — «Виртуальный патч» и заполним регулярное выражение — ^[^1–5]$ . Данной правило будет блокировать все POST запросы на URL — /api/Feedbacks с любыми значениями в теле json по ключу rating, кроме цифр от 1 до 5.

864d8963077a7a65b5481e2ceb6c4f98.pngeafb007a4a446a5e028346ffc168a299.png

Проверим. Генерируем такой же запрос с рейтингом 0 и наблюдаем, что в ответе возвращается ошибка 403. Также формируется событие в личном кабинете WAF. Развернув его, можно получить подробности заблокированного запроса.

82fd51b20f338abf55a5dd28ff7691aa.pnge9a47731ff5ec4c5970ef80d3d9bf7f4.png

Admin Registration

Данная задача заключается также в эксплуатации неправильной проверки ввода. Добавив лишнее поле в тело json POST запроса при регистрации аккаунта, можно получить права администратора. Перехватим запрос и добавим значение admin с ключом role. Ответ сервера говорит об успешной обработке и регистрации аккаунта с ролью администратора.

81cb1792c82f217e0912c887bf26071d.png720695e3775e857d09dd5b1b8bf949b6.png50eda97859dd043f16cb82f6379f74c9.png

Для решение данной задачи достаточно создать виртуальный патч, который блокирует POST запросы пользователей на URL /api/Users, в теле json которых будет ключ role. После создания виртуального патча видим, что запрос заблокирован.

5c7208ee885c4dca6514cdd6c12701ea.png444648bdac5d5fe218e56a1dd33d6809.pngd43f18ab8c482fc1ada3a1bae4f0085b.pngf4bfbb2c39b1529f2d351a60b0529530.png

Upload Type

Данная задача указывает на то, что активная проверка на тип загружаемого файла есть только на фронте. Но перехватив запрос, изменив в нем заголовок Content-Type в multipart и добавив файл в двоичном формате непосредственно в запрос, можно обойти установленные ограничения. 

229c945ce47b185fa626b0d9c207223d.pngdc27025144224fec863a74dee2877804.pngb51fed0424660302424ee2e9d4353c19.png

Изменим Content-Type и cкопируем двоичное представление juice.jpg, открыв картинку с помощью блокнота. Вставим в запрос.

8e91b2ff99cf2de9f34cde661428dc96.png

Важное преимущество WAF от компании Вебмониторэкс в том, что он использует регулярные выражения Pire от Яндекс (подробнее здесь — https://github.com/yandex/pire). И в данной разработке есть ключевая функция — инвертор регулярного выражения — значок тильды »~». Таким образом полностью раскрываются обе модели работы WAF — негативная и позитивная. В редких случаях, как в первой рассмотренной нами задаче, можно обойтись без него. Так мы создали позитивное правило с помощью конструкции [^ … ], где  — набор одиночных символов, которые не должны встречаться в искомом слове. То есть при создании блокирующего правила мы наоборот разрешаем только символы на месте . Проблема в том, что внутри конструкции можно использовать только одиночные символы, а не группу, которые могут составить слово. И проблема решается тильдой. Понятно также то, что негативная модель предусмотрена изначально.

Снова создадим пользовательское правило индикатора атаки на основе регулярного выражения. На это раз будет проверяться не поле в теле json, а заголовок Content-Type в multipart. Запишем регулярное выражение ~(^application/(pdf|zip)$) . Тильда инвертирует выражение. Поэтому допустимы только те запросы, которые содержат в заголовке Content-Type либо application/pdf, либо application/zip .

fb2dc87f56427209ad183a650054be0e.png5cec25801ca91b06ec0c48995545fbda.png

Проверим, как отрабатывает WAF. Отправим нелегитимный запрос снова. Запрос заблокирован.

03ee54f1728f37ddcbec00f4be8ac667.png

Изменение и добавление заголовков в ответ сервера

Для пользователей, знакомых с NGINX, известно, что в режиме обратного прокси, сервер может добавлять дополнительные заголовки к запросам, которые он проксирует дальше. Таким образом дополнительно защищая трафик. Но можно пойти с другой стороны…

В данном разделе посмотрим на еще одну функцию пользовательских правил платформы «Вебмониторэкс» — добавление/замена заголовков в ответе на запрос. Это позволяет настроить дополнительную защиту приложение от атак. 

Для демонстрации данной возможности развернем приложение Vulnbank, которое имитирует уязвимый онлайн-банк. Делается это с помощью докера одной командой.

docker run --name vulnbank -p 80:80 -d vulnbank/vulnbank

Теперь заходим в аккаунт с логином — j.doe и паролем — password. И создаем транзакцию, в комментариях к которой напишем вредоносный скрипт. Это так называемая Stored XSS атака. Написанный нами скрипт будет хранится в базе данных и исполнятся каждый раз, когда мы захотим посмотреть историю транзакций. Вредоносный скрипт вызывает открытие нового окна с официальным сайтом К2Тех.

567f3f559424dc95a0e7e9d8de46b047.png

Но перед тем, как отправим запрос с транзакцией, мы на примере посмотрим еще одну возможность WAF — игнорирование некоторых типов атак. В реальных кейсах это служит для игнорирования False Positive запросов, который поступают на защищенную точку входа. Но в нашем случае мы делаем это, чтобы WAF не заблокировал сразу нашу XSS инъекцию. Создаем правило с исключением. Данные запроса поступает в /vulnbank/online/api.php в строке urlencoded .

ca69ffd3e48d18c15fc4429eb5fca622.png0d0bfd8add6f93377aaaef1149b1bb95.pngcb6e884673fbcbd81eca42a84fcbd5c5.png

Отправляем транзакцию и переходим в раздел «История». Видим, что скрипт отрабатывает.

66a0e4ed02e6928f90f6c093e73cf0ff.png

В данном примере рассмотрим, как можно дополнительно защитить приложение от атаки хранимой XSS. Делается это с помощью заголовка Content-Security-Policy. С помощью значения script-src можно ограничить источник встраиваемых скриптов, в также добавить nonce. В примере приведен демонстрационный пример. Так в реальных кейсах не делают, так как nonce должен быть динамическим. Создадим правило со статическим nonce, который ограничивает исполнение скриптов с отличным значением или без него вовсе.

d0ef25ee7d10e4e922adea9e21027705.png

Проверяем. Скрипт не исполняется, новая окно не открывается. Видим также, что не формируется лишних запросов, которые вызывал бы вредоносный код.

a64a6b9c485847d55c6a6656f5e55540.png

© Habrahabr.ru