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

File Upload Bypass через подмену Content-Type

Обработчик загрузки файлов проверяет только расширение (.jpg, .png, .gif), но не реальное содержимое файла. HTML-файл с расширением .jpg будет принят и отдан браузеру.

mediumgolangPro
Задача
# File Upload: подмена типа файла через несоответствие расширения и содержимого ## Сценарий Вы тестируете интернет-магазин **SecureShop**: в приложении доступна загрузка медиа-файлов (аватары, изображения товаров) через API-эндпоинт. Загруженные файлы становятся доступны по прямому URL под директорией `/uploads/`. Команда уверена, что эндпоинт безопасен — на сервере есть фильтр расширений, разрешающий только изображения. По данным внутреннего аудита, доступ к админ-панели приложения требует флаг авторизации, который можно получить через специфичный сценарий — её требуется получить, имея только обычную учётную запись. ## Цель 1. Изучите, что именно сервер проверяет при загрузке файла: имя/расширение или реальный контент. 2. Найдите способ загрузить файл, который **сервер посчитает изображением** на основе своих проверок, но при отдаче **браузер интерпретирует как другой тип контента** — открыв канал для активного исполнения. 3. Используя этот канал, получите доступ к админ-функциональности и извлеките флаг. ## Теория Безопасная обработка загрузок файлов требует одновременной валидации **трёх независимых аспектов**: (1) имя файла (расширение, отсутствие path traversal), (2) реальный контент (magic-bytes — первые байты, идентифицирующие формат), (3) поведение при отдаче (`Content-Type` заголовок, `X-Content-Type-Options: nosniff`). Если защита покрывает только один аспект — обычно проще всего расширение — атакующий легко проходит фильтр, подавая файл с «правильным» расширением, но фактически содержащий другой тип контента. **Уязвимый паттерн:** ```go // Проверка только расширения — содержимое не валидируется ext := strings.ToLower(filepath.Ext(header.Filename)) if !allowedExts[ext] { return // reject } io.Copy(out, file) // сохраняем содержимое как есть ``` Усиливающий фактор — поведение браузера: при отдаче файла без явного `Content-Type` (или с общим `application/octet-stream`) браузер может выполнить **MIME sniffing**: посмотреть на первые байты содержимого и решить, что это HTML, в результате применяя HTML-парсер с исполнением встроенных скриптов. Заголовок `X-Content-Type-Options: nosniff` отключает это поведение, но если он не установлен, любой загруженный файл становится потенциальным каналом для XSS под доменом самого приложения — со всеми привилегиями same-origin. ## Точка входа атаки | Параметр | Значение | |----------|----------| | Учётные данные | `demo` / `demo` | | Эндпоинт загрузки | `POST /api/upload` (multipart/form-data) | | Директория отдачи | `/uploads/` (статика) | | Цель | получить access-флаг через канал stored XSS под доменом приложения, дающий доступ к admin-функциональности |
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru