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 candidates. 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 (milw0rm.com/exploits/34 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 "127.0.0.1" Thu Jul 10 02:33:24 2008 [pid 27930] [evil_payload] FAIL LOGIN: Client "127.0.0.1" $ 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/www.example.com/private/.rawlogs/access.log 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" (http://www.g-brain.net/tutorials/local-file-inclusions.txt). 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 "http://example.com/index.php?page=../../../proc/self/environ&cmd=ls" -H "User-Agent: PHP_RCE: " 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 privileges. 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/www.example.com/logs/www_access.log). 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: http://ush.it/team/ascii/hack-lfi2rce_proc/lfi2rce.sh A nice demo for the impatients: http://ush.it/team/ascii/hack-lfi2rce_proc/lfi2rce.demo.txt * http://www.g-brain.net/tutorials/local-file-inclusions.txt Last-Modified: Mon, 24 Mar 2008 12:52:49 GMT