FlowBase

Web hard

В платформе автоматизации FlowBase собираем потоки из нод и запускаем их вебхуками. Флаг лежит в `/flag.txt`, доступном служебному пользователю `flowsvc`. В сервисе открыта регистрация. Начинаем с создания учётной записи. ## Решение `robots.txt` подсказывает каталог `/dl/`. Файл, записанный в этот каталог, можно будет забрать через веб. Регистрируемся через `POST /api/register` с JSON-полями `username` и `password`. Из поля `token` ответа получаем bearer-токен и передаём его в `Authorization: Bearer ` при чтении потоков и их версий. `GET /api/flows` показывает только потоки текущего пользователя. Сразу после регистрации список пуст. Зато `GET /api/flows/{id}/versions` владельца не проверяет. Перебираем числовые ID от 1 до 40 с полученным токеном и находим чужой `backup-daily`. В JSON версий находим ноду `system.run` и берём `webhook_uuid` соответствующей версии. Проверяем её параметры. | Поле | Почему интересно | |---|---| | `owner = admin` | Поток принадлежит администратору | | `webhook_uuid` | Адрес запуска потока | | Нода `system.run` | Выполняет `curl $CURL_OPTS $BACKUP_URL` | IDOR дал UUID вебхука. Проверка его ключа отключена через `WebhookAuthEnable=false`, поэтому `POST /webhooks/{uuid}/run` запускает поток без авторизации. Тело запроса позволяет задать `env` для нод. Сервис проверяет, что первое слово команды равно `curl`, но аргументы берёт из переданных переменных. Подставляем локальный источник и файл назначения: ```json { "env": { "BACKUP_URL": "file:///flag.txt", "CURL_OPTS": "-s -o /app/static/dl/leak.txt" } } ``` Отправляем этот JSON в `POST /webhooks/{uuid}/run` с `Content-Type: application/json`, без заголовка авторизации. На сервере получается: ```bash curl -s -o /app/static/dl/leak.txt file:///flag.txt ``` Процесс `flowsvc` может прочитать флаг и записать файл в каталог статики. Вывод ноды в ответ вебхука не попадает. Сохранённый результат забираем через `GET /dl/leak.txt`. Доступ к версиям чужого потока раскрывает UUID, которого достаточно для запуска. Переданные переменные окружения становятся аргументами `curl`, позволяя скопировать закрытый файл в доступный каталог. [Солвер](solve/solve.py). ## Флаг `CAPLAG{flowb4s3_webhook_def4ult_0ff}`