Path Traversal (Иллюзия filepath.Clean)
Обход неумелого использования функции filepath.Clean.
mediumgolangPro
Задача
# Path Traversal: обход нормализации пути
## Сценарий
Вы аудируете **SecureFiles** — Go-сервис скачивания статических файлов. После предыдущего инцидента команда добавила «защиту» от обхода каталогов: пользовательский ввод нормализуется штатной функцией пути из stdlib перед конкатенацией с базовой директорией. Разработчики уверены, что традиционный traversal теперь заблокирован.
## Цель
1. Обойдите применённую нормализацию пути и сформируйте payload, дающий выход за пределы базовой директории.
2. Прочитайте произвольный файл вне разрешённой директории через эндпоинт скачивания.
3. Извлеките содержимое `/tmp/flag.txt`, чтобы получить флаг.
## Теория
Path Traversal возникает, когда пользовательский ввод используется для построения пути к файлу без надёжной проверки, что итоговый путь остаётся внутри разрешённой директории. Распространённое заблуждение — вызвать функцию нормализации (`Clean`/`normpath`/`realpath`) и считать, что защита готова. На самом деле такие функции схлопывают только избыточные сегменты (`./`, `//`, разрешённые `a/b/../c`), но **не удаляют** начальные восходящие сегменты `../`, потому что они являются синтаксически корректным относительным путём.
**Уязвимый паттерн:**
```go
// Нормализация применяется ДО конкатенации с базовой директорией
cleanName := filepath.Clean(userInput)
fullPath := basePath + "/" + cleanName
```
После нормализации `../../../etc/passwd` остаётся `../../../etc/passwd`, и при последующей конкатенации с базой ОС разрешает компоненты `..` относительно базовой директории при открытии файла — атака отрабатывает без изменений. В реальных системах типичны и кодированные варианты обхода (URL-encoding точек/слешей, двойное кодирование, юникод-эквиваленты), которые могут проходить через WAF до серверной обработки.
## Точка входа атаки
`GET /download?file=<имя файла>` — параметр `file` принимает произвольное имя файла и возвращает его содержимое в теле ответа.
**Цель:** прочитать `/tmp/flag.txt` и получить флаг из ответа сервера.