Перейти к содержимому
← Каталог golang File Upload

File Upload Bypass через двойное расширение

Обработчик загрузки использует filepath.Ext() для проверки расширения, но эта функция возвращает только последнее расширение. Файл test.html.jpg проходит проверку, а Go http.FileServer может определить Content-Type по первому расширению.

mediumgolangPro
Задача
# File Upload: обход allowlist через множественные расширения в имени ## Сценарий Вы тестируете интернет-магазин **SecureShop**: в приложении доступна загрузка медиа-файлов через API-эндпоинт. После предыдущего инцидента команда добавила «защиту» — фильтр расширений, разрешающий только изображения. Команда уверена, что allowlist расширений теперь полностью покрывает риск загрузки исполняемого контента. По данным внутреннего аудита, доступ к admin-функциональности приложения требует получения сессии с привилегиями — её требуется получить, имея только обычную учётную запись. ## Цель 1. Изучите, как именно сервер извлекает «расширение» из имени файла для allowlist-проверки. 2. Найдите способ передать файл, у которого «последнее расширение» соответствует allowlist, но реальное содержимое (или intermediate-расширение) — другого типа, исполняемого браузером. 3. Используя этот канал, получите доступ к admin-функциональности и извлеките флаг. ## Теория Стандартный подход к проверке типа файла «по расширению» в Go — функция, возвращающая часть имени **после последней точки**. Это семантически корректное определение «расширения файла» по соглашению UNIX/Windows, но в роли защитного фильтра оно работает плохо: файл может иметь несколько разделённых точкой суффиксов в имени (`report.pdf.exe`, `photo.html.jpg`, `archive.tar.gz`), и в зависимости от того, кто и как его обрабатывает, разные части имени могут интерпретироваться по-разному. **Уязвимый паттерн:** ```go // "payload.html.jpg" -> filepath.Ext возвращает ".jpg" -> проходит allowlist ext := filepath.Ext(header.Filename) if !allowedExts[ext] { return /* reject */ } io.Copy(out, file) // сохраняем оригинальное имя как есть ``` Атакующий пользуется тем, что сервер при сохранении хранит оригинальное имя `payload.html.jpg`. При последующей отдаче файла через `http.FileServer` — расширение становится контекстом для `Content-Type`-определения; разные веб-серверы и middleware-цепочки могут реагировать по-разному (Apache с `MultiViews` и `mod_mime` будет искать ассоциацию для **каждого** суффикса, и `.html` сделает файл HTML-документом). В Go-сценарии без `nosniff` — браузер при открытии URL применит MIME sniffing к содержимому; HTML-разметка внутри будет распознана и исполнена. ## Точка входа атаки | Параметр | Значение | |----------|----------| | Учётные данные | `demo` / `demo` | | Эндпоинт загрузки | `POST /api/upload` (multipart/form-data) | | Директория отдачи | `/uploads/` (доступна по прямому URL) | | Цель | получить access к admin-функциональности через канал, открытый загруженным файлом |
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru