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

LFI через PHP stream wrappers (php://filter)

Наивная фильтрация ../ не блокирует php://filter — атакующий читает исходники PHP-файлов в base64.

mediumphpPro
Задача
# Лаба: LFI через PHP stream wrappers ## Сценарий Команда SecureShop добавила раздел «Документация» по адресу `/doc?name=...`. Разработчик прочитал пару статей про path traversal, добавил проверку, что параметр не содержит `..` и заканчивается на `.php`, и посчитал задачу закрытой. Однако `include()` в PHP понимает не только пути в файловой системе — он работает и со **stream wrappers**, которые позволяют читать файлы через встроенные фильтры PHP. Stream wrappers — это специальные URI-схемы (`php://`, `phar://`, `data://`, `zip://`, `compress.zlib://`), которые PHP интерпретирует как источники данных. Самый опасный из них — `php://filter`. Он позволяет прогнать содержимое любого читаемого файла через встроенные конвертеры (например, `convert.base64-encode`) перед тем, как `include()` попытается выполнить результат. Поскольку base64-закодированный PHP-код не является валидным синтаксисом, интерпретатор не выполняет его — но он попадает в буфер вывода, и атакующий читает исходники. ## Уязвимый паттерн Обработчик `/doc?name=...` принимает имя статьи из GET-параметра и пропускает его через две поверхностные проверки: блокирует подстроку `..` и требует, чтобы значение оканчивалось на `.php`. После этого функция конструирует `include_path` (включающий корень приложения) и вызывает `include()` с пользовательским значением. Проверка ищет литеральные `..` и `/`, но никак не препятствует префиксу `php://`. Параметр вида `name=php://filter/convert.base64-encode/resource=...` не содержит `..`, оканчивается на `.php` и проходит обе проверки — а PHP интерпретирует его как stream wrapper и прогоняет произвольный читаемый файл через base64-кодировщик. ## Цели 1. Подтвердить, что наивная защита (`..` blacklist + суффикс `.php`) пропускает stream wrappers. 2. Получить base64-закодированные исходники серверных файлов (`internal/handlers/handlers.php`, `internal/env/env.php`, `cmd/main.php`) и убедиться, что в ответе действительно лежит PHP-исходник. 3. По прочитанному исходному коду понять, что флаг лабы хранится в переменной окружения `LAB_FLAG`. 4. Через тот же stream wrapper прочитать `/proc/self/environ` и извлечь значение `LAB_FLAG=flag{...}`. ## Точка входа * **Эндпоинт:** `GET /doc?name=<article>` * **Легитимные значения:** `index.php`, `api.php`, `faq.php` * **Учётные данные обычного пользователя:** `demo` / `demo` (логин не требуется для эксплуатации — эндпоинт `/doc` публичный) * **Маркер успешного чтения:** base64-блок длиной 200+ символов в ответе * **Источник флага:** переменная окружения `LAB_FLAG` процесса Apache (читается функцией `getFlag()` в `internal/env/env.php`) ## Почему это важно LFI через stream wrappers — реальный класс уязвимостей, регулярно встречающийся в production-приложениях на PHP. CWE-98 («Improper Control of Filename for Include/Require Statement») и CVE-базы содержат сотни записей именно про эту технику. Сюда же относятся знаменитые атаки на phpMyAdmin, Drupal и другие CMS.
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru