# Lfi2rce Phpinfo

> How to exploit Local File Inclusion (LFI) to Remote Code Execution (RCE) using PHPInfo() output. Use this skill whenever you need to escalate LFI vulnerabilities to RCE, especially when phpinfo() pages are accessible, or when you're testing for file inclusion vulnerabilities that could lead to code execution. Make sure to use this skill when you find LFI sinks combined with phpinfo() endpoints, or when you need to convert file inclusion into command execution on PHP applications.

- Skill: `abelrguezr/lfi2rce-phpinfo` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/lfi2rce-phpinfo`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/lfi2rce-phpinfo/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/lfi2rce-phpinfo

---


# LFI to RCE via PHPInfo

This skill teaches you how to escalate Local File Inclusion (LFI) vulnerabilities to Remote Code Execution (RCE) by leveraging PHP's `phpinfo()` output to discover temporary file paths created during file uploads.

## When to Use This Technique

Use this approach when you have:
- A reachable page that outputs `phpinfo()` (e.g., `/phpinfo.php`, `/info.php`, `/debug.php`)
- An LFI primitive you control (user-controlled `include`, `require`, `file_get_contents`, etc.)
- PHP file uploads enabled (`file_uploads = On`)
- The ability to include files from the upload temp directory

## Theory

When PHP receives a `multipart/form-data` POST with a file field, it:
1. Writes the content to a temporary file in `upload_tmp_dir` (or system temp directory)
2. Exposes the path in `$_FILES['<field>']['tmp_name']`
3. Automatically removes the file at the end of the request unless moved/renamed

**The trick**: `phpinfo()` prints `$_FILES`, including `tmp_name`. By inflating request headers/parameters (padding), you can cause early chunks of `phpinfo()` output to flush to the client before the request finishes. This lets you read `tmp_name` while the temp file still exists, then immediately hit the LFI with that path to execute the payload.

**Common temp paths**:
- Linux/Unix: `/tmp/php*.tmp` or configured `upload_tmp_dir`
- Windows: `C:\Windows\Temp\php*.tmp`

## Attack Workflow

### Step 1: Prepare Your Payload

Create a PHP payload that persists a shell quickly (writing a file is faster than waiting for a reverse shell):

```php
<?php file_put_contents('/tmp/.p.php', '<?php system($_GET["x"]); ?>');
```

### Step 2: Send Large Multipart POST to phpinfo()

Send a large `multipart/form-data` POST directly to the `phpinfo()` page. Inflate headers/cookies/params with ~5–10KB of padding to encourage early output flushing.

### Step 3: Race Condition - Parse and Include

While the `phpinfo()` response is still streaming:
1. Parse the partial body to extract `$_FILES['<field>']['tmp_name']` (HTML-encoded)
2. As soon as you have the full absolute path (e.g., `/tmp/php3Fz9aB`), fire your LFI to include that path
3. If `include()` executes the temp file before deletion, your payload runs and drops `/tmp/.p.php`

### Step 4: Use the Dropped Shell

Access the persistent shell:
```
GET /vuln.php?include=/tmp/.p.php&x=id
```

## Using the PoC Script

The bundled script `scripts/lfi2rce-phpinfo.py` automates this attack. Configure these variables:

| Variable | Description | Example |
|----------|-------------|---------|
| `HOST` | Target hostname | `target.local` |
| `PORT` | Target port | `80` |
| `PHPSCRIPT` | Path to phpinfo() endpoint | `/phpinfo.php` |
| `LFIPATH` | LFI sink path (sprintf-style, `%s` = tmp path) | `/vuln.php?file=%s` |
| `THREADS` | Concurrent workers | `10` |
| `PAYLOAD` | PHP code to execute | See defaults |

### Running the Script

```bash
python3 scripts/lfi2rce-phpinfo.py
```

### Customizing for Your Target

**If the LFI sink appends `.php`**: Remove null byte handling; `include()` will execute PHP regardless of temp file extension.

**If you need null bytes** (older PHP): Add `%00` to the LFI path to cut off unwanted extensions.

**Adjust padding**: If output doesn't flush early, increase `PADDING` size or add more large headers.

## Troubleshooting

| Problem | Solution |
|---------|----------|
| Never see `tmp_name` | Ensure you're POSTing `multipart/form-data` to `phpinfo()`. `$_FILES` only appears with upload fields. |
| Output doesn't flush early | Increase padding, add more large headers (Cookie, User-Agent, Accept-Language, Pragma), or send concurrent requests. |
| LFI path blocked | Check `open_basedir` or `chroot` restrictions. Point LFI to an allowed path or try a different LFI→RCE vector. |
| Temp directory not `/tmp` | `phpinfo()` prints the full absolute `tmp_name` path; use that exact path in the LFI. |
| HTML-encoded arrow `=&gt;` | The script handles both `=>` and `=&gt;` encodings automatically. |

## Defensive Notes

- **Never expose `phpinfo()` in production**. If needed, restrict by IP/auth and remove after use.
- **Keep `file_uploads` disabled** if not required. Otherwise, restrict `upload_tmp_dir` to a path not reachable by `include()` in the application.
- **Treat any LFI as critical**; even without `phpinfo()`, other LFI→RCE paths exist.
- **Validate and sanitize** all `include`/`require` paths with strict allowlists.

## References

- LFI With PHPInfo() Assistance whitepaper (2011) – [Packet Storm](https://packetstormsecurity.com/files/download/104825/LFI_With_PHPInfo_Assitance.pdf)
- PHP Manual – POST method uploads: [php.net](https://www.php.net/manual/en/features.file-upload.post-method.php)
- Original PoC: `phpinfolfi.py` (see whitepaper)

