Remote File Inclusion через include() с allow_url_include
Параметр page передаётся в include() при включённом allow_url_include — атакующий загружает и выполняет произвольный PHP-код с удалённого сервера.
hardphpPro
Задача
# Remote File Inclusion через include() с allow_url_include
## Сценарий
Интернет-магазин SecureShop использует PHP-приложение для отображения информационных страниц (`/page?page=home`, `/page?page=about` и т.п.). Каждая страница — это отдельный `.php`-шаблон в каталоге `templates/pages/`. Сам обработчик решает, какой шаблон подгрузить, по значению query-параметра.
На этапе миграции с внешнего CDN разработчик включил в `php.ini` директиву `allow_url_include=On`, чтобы временно подтягивать шаблоны по HTTP-адресу. После окончания миграции директиву забыли отключить, а сам обработчик параметра `page` не был пересмотрен и продолжает напрямую передавать пользовательский ввод в функцию подключения файлов.
В результате возникла классическая уязвимость **Remote File Inclusion (CWE-98)**: значение параметра, контролируемое атакующим, склеивается с расширением `.php` и попадает в `include()`. При включённой `allow_url_include` PHP воспринимает любые строки, начинающиеся с `http://`, `https://`, `ftp://`, `data://`, `phar://` и других обёрток, как валидный источник кода — скачивает содержимое и выполняет его в контексте приложения. Это даёт **немедленный Remote Code Execution** через единственный HTTP-запрос.
## Цели
1. Подтвердить наличие уязвимости Remote File Inclusion, заставив приложение подгрузить и выполнить PHP-код с внешнего HTTP-сервера, контролируемого атакующим.
2. Продемонстрировать альтернативный вектор — выполнение кода через `data://` wrapper без необходимости поднимать внешний сервер, упаковав payload прямо в URL через base64.
3. Получить значение флага лабы, прочитав переменную окружения `LAB_FLAG` внутри контекста уязвимого процесса с помощью одного из RFI-векторов.
## Что нужно знать
- В PHP функции `include`, `require`, `include_once`, `require_once` способны загружать код не только из локальной файловой системы, но и из произвольного URL — при условии, что в `php.ini` включена директива `allow_url_include`.
- PHP поддерживает stream wrapper-ы: `http://`, `https://`, `ftp://`, `data://`, `php://input`, `phar://` и другие. Все они становятся валидными «источниками» для подключения, как только `allow_url_include=On`.
- Конкатенация пользовательского ввода с фиксированным суффиксом (например, `$page . '.php'`) почти всегда обходится через query-часть URL (`?x=`), которая «поглощает» лишние символы при HTTP-запросе и игнорируется парсерами wrapper-ов вроде `data://`.
## Данные для входа
| Параметр | Значение |
|----------|----------|
| Обычный пользователь | `demo` / `demo` |
| Уязвимый эндпоинт | `/page?page=home` |
| php.ini (установлено в образе) | `allow_url_include=On`, `allow_url_fopen=On` |
| Локация флага | переменная окружения `LAB_FLAG` внутри контейнера |