Нам попал в руки прототип будущей соц-сети от экс-сотрудников Твиттера. Еще не все функции реализованы, но можно заценить.
Администратор новой соцсети даже запостил там флаг.
Поменять LOGIN_URL
config.env на публичный адрес http://<ip>:4321/login
(необязательно).
cd deploy
docker-compose -p web_onlytweets up --build -d
Архив из директории public/ и IP:PORT сервера
Идея задачи - эксплуатация CSRF с включенными CSRF-токенами.
На сайте есть возможность делиться твитами и есть бот, который ходит по ссылкам.
В задаче есть XSS, но его эксплуатация должна быть невозможной из-за CSP.
Перед нами типичный таск на XSS: есть платформа, на платформе есть бот, ходящий по ссылкам от участников.
Важно заметить, что бот использует firefox, а не Chromium-based браузер.
После просмотра кода можно найти XSS, однако ее эксплуатация маловероятна.
Тогда можно вспомнить про другую client-side атаку - CSRF. Для нее у нас есть несколько важных составляющих:
- У нас есть возможность отправить бота на любую страницу (не только на страницы приложения).
- Бот использует firefox, а на сервере не указана SameSite policy, из-за чего CSRF с другого домена возможен.
- В приложении есть функционал 'поделиться' постом. Мы знаем ID поста админа, можем заставить его поделиться с нами постом.
Проблема в том, что в задании используется защита от CSRF с использованием CSRF-токенов.
Можно заметить что в задании нестандартно используется фреймворк Flask:
- Вместо request.form/request.args всегда используется request.values (получить значение либо из body, либо из URL).
- Обработчики GET/POST запросов сначала проверяют что пришел GET-запрос.
Flask, как и многие другие веб-фреймворки, обрабатывает HEAD-запросы, если обработчик уже поддерживает GET-запросы.
Тогда, если мы отправим HEAD-запрос с нужными нам URL-параметрами(?share_to=ouruser&tweet_id=1), то
условие if request.method == 'GET'
не выполнится и будет вызван код для шэринга твита. Так как в обработчике
используется request.values, то параметры будут взяты из URL.
CSRF-защита не сработает на такой запрос, т.к. обычно работает только на POST/PUT/DELETE.
Решение:
- Создать HTML-файл, в котором выполнить JS, отправляющий HEAD-запрос с нужными параметрами на backend:4321/share. Тем самым заставить бота поделиться с нами его флагом.
- Отправить ссылку на HTML-файл боту.
- Прочитать флаг, который будет в приватной ленте.
CUP{bb1f209d615d1f6338170c4105965a}