PHP wrappers β LFI to RCE
After using LFI mainly for local file disclosure, the next step is often remote code execution on the back-end. Viability depends on language, sink (include vs read-only APIs), and server configuration.
Paths that do not need stream wrappers
Before reaching for wrappers, enumeration still matters: read config.php for DB passwords (possible reuse as OS user passwords), home .ssh/id_rsa when permissions allow, then pivot via SSH or another remote session.
allow_url_include and php.ini
Several PHP stream attacks require allow_url_include = On (off by default). It also gates php://input abuse and RFI. Some apps (e.g. certain WordPress plugins/themes) enable it anyway.
Confirm by reading php.ini through LFI, using php://filter/read=convert.base64-encode/resource=... so the response stays usable (similar to reading other .ini / PHP files):
- Apache:
/etc/php/X.Y/apache2/php.ini - Nginx / PHP-FPM:
/etc/php/X.Y/fpm/php.ini
Try current X.Y first, then older versions. Prefer cURL or Burp over a browser for long Base64 output. Decode and search:
echo '<BASE64>' | base64 -d | grep allow_url_include
data:// β inline PHP
When allow_url_include is on, data:// can supply PHP source to an execution-capable include. Use text/plain;base64, and URL-encode the Base64 payload.
Example shell one-liner to encode:
echo '<?php system($_GET["cmd"]); ?>' | base64
Request shape (conceptually): vulnerable parameter set to data://text/plain;base64,<PAYLOAD> plus &cmd= for the command (if the app merges GET into the included context as expected).
php://input β POST body as PHP
Same allow_url_include dependency. Point the include at php://input and send raw PHP in the POST body. If $_GET["cmd"] is not merged into the executed code path, bake the command into the POST body (e.g. <?php system('id'); ?>) instead of a tiny dynamic shell.
expect:// β command execution stream
expect is an optional extension (extension=expect in php.ini). Presence in config does not prove it loads at runtimeβtest with:
expect://id
(or the equivalent in your vulnerable parameter). No separate web shell payload is required; the wrapper is built for command-style use. Same idea appears elsewhere (e.g. XXE with expect).
Related topics
The php://filter chain for source disclosure (without RCE) is covered in php-filters-lfi.md. Phar and zip stream tricks paired with uploads and LFI are covered in lfi-file-uploads.md.