Remote File Inclusion (RFI) is where a web app allows the inclusion of remote URLs.
RFI got two benefits:
- Enumerating local-only ports and web applications (i.e. SSRF)
- Gaining remote code execution by including a malicious script that we host
If we refer to the table on the first section, we see that the following are some of the functions that (if vulnerable) would allow RFI:
Function | Read Content | Execute | Remote URL |
---|---|---|---|
PHP | |||
include() /include_once() | ✅ | ✅ | ✅ |
file_get_contents() | ✅ | ❌ | ✅ |
Java | |||
import | ✅ | ✅ | ✅ |
.NET | |||
@Html.RemotePartial() | ✅ | ❌ | ✅ |
include | ✅ | ✅ | ✅ |
As we can see, almost any RFI vulnerability is also an LFI vulnerability. |
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 modern web apps, remote URL inclusion is usually disabled by default.
Any remote URL inclusion in PHP requires allow_url_include
setting is enabled.
Let’s check on this by reading PHP configuration file using LFI and decoding it as how we did before:
However, this doesn’t determine RFI since the vulnerable function may not allow remote URL.
Best way to try including remote URL and see if we can get its content.
Start with local URL such as http://127.0.0.1:80/index.php
.
RCE w RFI
Let’s create reverse shell with PHP:
Now, we can start a server on our machine with a basic python server with the following command, as follows:
We can execute commands using the following link:
FTP
We may also host our script through the FTP protocol. We can start a basic FTP server with Python’s pyftpdlib
, as follows:
This may also be useful in case http ports are blocked by a firewall or the http://
string gets blocked by a WAF.
We can execute commands as such:
If the server requires valid authentication, then the credentials can be specified in the URL, as follows:
SMB
If the vulnerable web app is on Windows, we don’t need allow_url_include
setting to be enabled because we can use the SMB protocol for RFI.
We can spin up an SMB server using Impacket's smbserver.py
, which allows anonymous authentication by default, as follows:
Now, we can include our script by using a UNC path (e.g. \\<OUR_IP>\share\shell.php
), and specify the command with (&cmd=whoami
) as we did earlier: