Перейти к содержимому
← Каталог php Deserialization

PHP Deserialization: Phar RCE через Phar::getMetadata()

Эндпоинт просмотра инвойсов пытается «прочитать структурированные метаданные» и вызывает Phar::loadPhar() + getMetadata() на пути из параметра без проверки расширения. Атакующий загружает PHAR-архив под видом .jpg с объектом InvoiceCache в metadata — getMetadata() делает unserialize(), триггерит __destruct() → system() → RCE.

hardphpPro
Задача
# Атака: Phar Deserialization через file_exists() ## Сценарий SecureShop добавил функцию «Мои инвойсы». Пользователь может загрузить файл (формально инвойс в формате JPEG/PDF) и просмотреть его на странице `/invoice?file=<имя>`. Под капотом обработчик просмотра пытается «распознать структурированные метаданные инвойса» — если загруженный файл является PHAR-архивом, приложение вызывает `Phar::loadPhar($path)` и затем `Phar::getMetadata()`, чтобы вывести информацию о компании и дате выставления. В обычном режиме это работает даже на файлах с расширением `.jpg`, потому что `Phar::loadPhar()` распознаёт PHAR по сигнатуре `__HALT_COMPILER()` в теле файла, а не по расширению. Классика PHP-безопасности: вызов `getMetadata()` (или любая попытка прочитать metadata PHAR-архива) автоматически выполняет `unserialize()` над её содержимым. И это означает вызов magic-методов (`__wakeup`, `__destruct`, `__toString`) у классов, которые есть в приложении. В коде SecureShop есть класс `InvoiceCache` — внутренняя утилита для чистки устаревшего кэша. Его `__destruct()` вызывает `system($this->cleanupCmd)`. Классическая POP-gadget: если заставить PHP десериализовать объект `InvoiceCache` с контролируемым полем `cleanupCmd` — получим произвольное выполнение команд. ## Цель 1. Создать PHAR-архив, в метаданные которого положить объект `InvoiceCache` со свойством `cleanupCmd`, выполняющим чтение флага. 2. Загрузить его через `/invoice/upload`, замаскировав под `.jpg`. 3. Триггернуть десериализацию, запросив `/invoice?file=<ваш_файл>` — handler сам вызовет `Phar::loadPhar()` + `getMetadata()` на загруженном «изображении» и десериализует gadget. 4. Добиться того, чтобы gadget записал содержимое `/flag.txt` в доступное для чтения место (например, `/tmp/pwn.txt`), и прочитать оттуда флаг через тот же endpoint `/invoice?file=/tmp/pwn.txt`. ## Данные для входа - Зарегистрируйте нового пользователя на `/register` — роли `user` достаточно. - Лабораторный флаг лежит в `/flag.txt` (файл присутствует в контейнере). ## Что должно получиться В каком-либо доступном месте (`/tmp/pwn.txt` и т. п.) появится флаг вида `flag{...}`. Скопируйте его в поле ответа. ## Уязвимый endpoint - `GET /invoice?file=<path>` — уязвим: вызывает `Phar::loadPhar()`/`getMetadata()` на пути, пришедшем от пользователя, без проверки расширения и происхождения. - `POST /invoice/upload` — принимает любой бинарь под произвольным расширением. ## Уязвимый файл Обработчик просмотра инвойсов и gadget-класс кэш-слоя приложения.
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru