- a beautiful place

LFI2RCE (Local File Inclusion to Remote Code Execution) advanced exploitation: /proc shortcuts

August 18, 2008 at 12:47 pm - Filed under Hacks, Language EN - 1388 words, reading time ~4 minutes - Permalink - Comments
This paper exposes the ability from the attacker standpoint to use /proc in order to exploit LFI (Local File Inclusion) vulnerabilities. While using /proc for such aim is well known this one is a specific technique that was not been previously published as far as we know. A tool to automatically exploit LFI using the shown approach is released accordingly. Update: a third (known) technique has been dissected here: http://www_ush_it/2008/07/09/local-file-inclusion-lfi-of-session-files-to-root-escalation/
LFI2RCE advanced exploitation: /proc shortcuts

On UNIX systems, especially on Linux /proc is the preferred userspace
interface used for a number of things, especially process information.
This article will expose a technique that uses /proc/%{PID}/fd/%{FD_ID}
to implicitly find the location of the logfile containing the attacker's
payload. Enjoy reading this article by kuza55 and ascii (-;

It's known that LFI (Local File Inclusion) vulnerabilities can be
exploited in a way that converts them in RCE (Remote Code Execution).

The malicious payload must exist locally, on the filesystem, but since
the attacker is commonly not able to directly upload/create a file,
logs are used. By their intrinsic nature logfiles  contain data
that is driven by users (eg: the log will contain user inputs of some
sort). Logfiles that don't present this behaviour are not valid

The trick is to make these logs contain a base payload that will be
later interpreted and executed when the logfile is included. This
technique itself is know from many years ( is
dated 2003-05-29 but it's even older).

On a UNIX system multiple logfiles can be used for this scope: xfer log
("Transfer log") using specially crafted filenames during FTP transfers,
fail.log using a crafted username and performing a failed login on the
FTP server, etc.

While the path of these files is almost always known (they stay in
/var/ with weak permissions, masked 022) the service could be not
present or unreachable from outside (think of an IP that exposes only
https?). For this reason access_log and error_log are the most used to
perform this type of attack since it's auto-contained (uses only
resources provided by the webserver, a component that is hardly missing
in this scenario!).

If needed let few commands make things even clearer:

# echo -en "USER evil_payload\nPASS secr3t\n\n" | nc localhost 21
220 (vsFTPd 1.2.3)
331 Please specify the password.
530 Login incorrect.
530 Please login with USER and PASS.
$ cat /var/log/vsftpd.log
Thu Jul 10 02:33:22 2008 [pid 27931] CONNECT: Client ""
Thu Jul 10 02:33:24 2008 [pid 27930] [evil_payload] FAIL LOGIN: Client ""
$ curl "http://localhost/index.php?page=../../../var/log/vsftpd.log%00"

Note1: This general concept is often applied to PHP applications but is
valid also on other environments.

Note2: On Windows the story is similar and LFI2RCE conversions still
apply but obviously not the specific /proc technique presented.

To overcome the need to know the location of (access|error)_log (could be
guessable by bruteforcing against a list of known locations or obtained
from configuration files) it's possible to directly access it by its
file descriptor entry in /proc (a symlink to the real location).

Warning! Achtung! Attenzione! This means that the proposed technique
can't bypass any filesystem acl. It won't magically exploit the target.
The "injected" logfile must be readable by the interpreter as in any
normal LFI (for example won't work on Debian default vhost logs since
they are readable only by root).

Including /proc/31508/fd/5 the lstat64() and readlink() magic will
drive directly to the obscure and hard to guess location of access_log
(/home/ in this example).

In this attack the only variables are the process ID of a disposable
apache thread/mod_* and the file descriptor number (with the first three
reserved for stdin,out,err). As said before the process ID must be the
one of some application with an open file descriptor to the target and
Apache satisfies this requirement, this means that in case of mod_* it's
possible to directly use /proc/self since interpreter execution happens
inside Apache. When CGIs are used it's possible to go back up to the
Apache PID reading the 4rd column /proc/self/stat (if necessary iterate).

Since mod_php is the common case /proc/self is normally enough to carry
a successful attack, this makes the process uninfluenced by the presence
of Grsec user only /proc for example.

The second variable was the file descriptor number and greatly depends
on the target setup and load since file descriptors can belong to a
range of resources like pipes, sockets and naturally files. Some of the
fd points to logfiles and only two of them are the ones of the target
vhost. At the moment of writing we are unaware of methods to directly
guess the right number but the tool attached to this document speeds up
the process and automatically gives hints on the logfile type and usage.

Note that fd to logfiles are the first opened by apache and this is
especially true for non threaded MPMs like prefork. In such condition
the right fd number mainly depends on the number of vhosts loaded before
the one containing the vulnerable application under attack.

As final attack the right /proc/self/fd/X will be included and the
injected payload executed.

While writing this article and trying to give a complete and accurate
information a paper came to our attention: "LOCAL FILE INCLUSIONS
by G-Brain" (

It exposes a similar and possibly better technique we were not aware
of that is self-contained (doesn't require two different stages, one
to inject the payload in the log and one to actually include the
logfile) and non resilient (doesn't leave any payload in logs).

Summarizing /proc/self/environ contains user inputs (like an env var
named HTTP_USER_AGENT containing the data specified in the User-Agent
request header) that turn it in a useful volatile storage for LFI2RCE
attacks. It also contains other user controlled data beyond UA.

curl ""
-H "User-Agent: PHP_RCE: <?php passthru(\$_GET['cmd']) ?>"

The greatest advantage of this attack is that the whole path is static
and known, on the other side I had no luck in making it work on most of
my machines (Failed to open stream: Permission denied).

Now that you known the details of /proc LFI exploitation it's time to
explain the disadvantages correlated to /proc and the setups exposed
techniques will not work.

Logfiles owned by root and readable only by root: this is the vanilla
setup (at least for Gentoo and Debian) for the default vhost. Experience
teaches us that additional vhosts are often configured manually and
differently. This is possible since the fd's are opened before dropping

Safe mode/openbasedir: if openbasedir is correctly configured /proc is
no more accessible, on the other side logfiles could reside in an
allowed path (ex: open_basedir=/home, access_log at
/home/ Note that mass vhoster
clone a "skeletor" when creating new users, so the path to logfiles
could be guessed also by subscribing to the service.

Chroot without proc: the interpreter could run inside a chroot, in this
case /proc could be unexisting or the files linked by proc unreachable.

Grsec user only /proc plus CGI setup: if the interpreter process
belongs to a specific user that is different from the one running Apache
it will be impossible to access /proc/apache_pid/*.

Theoretical details are over, time for the code! To demonstrate our
technique (LFI2RCE using /proc/self/fd) this demo tool has been coded,
it's in bash, if that disgusts you feel free to convert it into your
favorite language (-; 

The tool:

A nice demo for the impatients:

  Last-Modified: Mon, 24 Mar 2008 12:52:49 GMT
A text version of the above article can be found here:
THP USH Wisec DigitalBullets