I have tried to run a vulnerability scanning script (Uniscan 6.0) on some websites and then I found a site which is exploitable with this following path. (included a word "invalid" , params/website are both censored)

3 Answers
3

Fascinating! @catalyze has dug up a truly intriguing, lovely situation here. I wanted to take the time to summarize what's going on here, on this site. (Full credits to @catalyze and Francesco "ascii" Ongaro; I'm just summarizing what they explained.)

Summary. This is not an everyday LFI attack. Instead, this is something more unusual and clever. Here we have a vulnerability that cannot be exploited through standard LFI methods; you need more trickiness to work out how to exploit it.

Background. First, I need to tell you two facts about PHP's file handling that were discovered by Francesco "ascii" Ongaro and others:

Fact 1. You can add stuff to the end of a filename. Everyone knows that /./etc/passwd is just another way to refer to the /etc/passwd file. But, here are some you may not have known about.

On PHP, it turns out that /etc/passwd/ also refers to the /etc/passwd file: trailing slashes are stripped off. Wild, huh? This doesn't work on base Unix, so it is a bit surprising that PHP would accept such a filename, but it appears that PHP is itself stripping off trailing slashes before opening the file.

You can append any number of trailing slashes: /etc/passwd//// is also OK.

And, you can append ./ (as many times as you want). For instance, /etc/passwd/., /etc/passwd/./, and /etc/passwd/././. all refer to /etc/passwd. Go nuts! PHP doesn't care.

Fact 2. Long paths are truncated. On most PHP installations, if the filename is longer than 4096 bytes, it will be silently truncated and everything after the first 4096 bytes will be discarded. No error is triggered: the excess characters are simply thrown away and PHP happily continues on.

The attack. Now I am ready to describe the attack. I'll show you the vulnerable code, why standard LFI attacks don't work, and then how to build a more-clever attack that does work. The result explains what @catalyze saw in his pentest.

The vulnerable code. Suppose we have code that looks something like this:

<?php
include("includes/".$_GET['param1'].".php");
?>

This looks like a local file include (LFI) vulnerability, right? But the situation is actually a bit trickier than it may at first appear. To see why, let's look at some attacks.

Standard attacks. The standard, naive way to try to exploit this LFI vulnerability is to supply a parameter looking something like ?param1=../../../../var/www/shared/badguy/evil. The above PHP code will then try to include the file includes/../../../../var/www/shared/badguy/evil.php. If we assume that the file /var/www/shared/badguy/evil.php exists and is controlled by the attacker, then this attack will succeed at causing the application to execute malicious code chosen by the attacker.

But this only works if the attacker can introduce a file with contents of his choice onto the filesystem, with a filename ending in .php. What if the attacker doesn't control any file on the filesystem which ends in .php? Well, then, the standard attacks will fail. No matter what parameter value the attacker supplies, this is only going to open a filename that ends with the .php extension.

A more sophisticated attack. With the additional background facts I gave you earlier, maybe you can see how to come up with a more sophisticated attack that defeats this limitation.

Basically, the attacker chooses a very long parameter value, so that the constructed filename is longer than 4096 bytes long. When the filename is truncated, the .php extension will get thrown away. And if the attacker can arrange for the resulting filename to refer to an existing file on the filesystem, the attacker is good.

Now this might sound like a far-fetched attack. What are the odds that we can find a filename on the filesystem whose full path happens to be exactly 4096 bytes long? Maybe not so good?

This is where the background facts come into play. The attacker can send a request with ?param1=../../../../etc/passwd/./././././<...> (with the ./ pattern repeated many thousands of times). Now look at what filename gets included, after the prefix is prepended and the .php file extension is added: it will be something like includes/../../../../etc/passwd/./././././<...>.php. This filename will be longer than 4096 bytes, so it will get truncated. The truncation will drop the file extension and leave us with a filename of the form includes/../../../../etc/passwd/./././././<...>. And, thanks to the way PHP handles trailing slashes and trailing ./ sequences, all that stuff at the end will be ignored. In other words, this filename will be treated by PHP as equivalent to the path includes/../../../../etc/passwd. So PHP will try to read from the password file, and when it finds PHP syntax errors there, it may dump the contents of the password file into an error page -- disclosing secret information to an attacker.

So this technique allows to exploit some vulnerabilities that otherwise could not be exploited through standard methods. See the pages that @catalyze links to for a more detailed discussion and many other examples.

This also explains why @catalyze was not able to exploit the attack by sending something like ?param1=../../../../etc/passwd: a .php extension got added on, and the file /etc/passwd.php did not exist, so the attack failed.

Summary. Peculiarities in PHP's handling of file paths enable all sorts of subtle attacks on vulnerabilities that otherwise would appear unexploitable. For pentesters, these attack techniques may be worth knowing about.

For developers, the lesson is the same: validate your inputs; don't trust inputs supplied by the attacker; know about classic web vulnerabilities, and don't introduce them into your code.

No white/black lists,open_base_dir or any restrict access configuration

There is magic_quotes escape nullbytes as addslashes() is implicitly called on all GPC and SERVER inputs. (in this case etc/passwd%00 would become etc/passwd\0 , so it cannot evaluate as correct file.)

include_path (within php.ini) contains at last one absolute path to trigger a part of complex vulnerable in sourcecode of PHP (for example, include_path = ".:/usr/share/php")

Wow! Brilliant catch, @catalyze. That explains everything you saw. P.S. You might notice that the attack string that does work is exactly 4096 bytes long -- exactly as long as it needs to be to exploit the path truncation property, and no longer. Neat.
–
D.W.Jul 30 '12 at 3:31

You could potentially exploit this LFI to upload your webshell, and run system commands on the web shell. The simplest way to do this is to inject into access.log, and accessing access.log. The simplest way to do this is to modify the User Agent, or maybe even the GET request, to include some PHP code that would help you setup a stager. For example, a telnet into the website, and the following request, should inject into access.log:

GET/ <?php phpinfo() ?>

Obviously, all this will do is get you the PHP Information from access.log, but you get the idea. Now, on the same lines, you could easily do something like:

and then upload a base64 encoded PHP script into it, and get your web shell up there. I'll leave it up to you to figure out the rest of it, it shouldn't be hard at all. There's a really multi-part tutorial for this on Kaotic Creations that you should really read, if you are interested in learning more about this.

This is very useful stuffs but I want to know how that very long path ../../etc/passwd/././././blah blah could included (exploit with LFI) but ../../etc/passwd or ../../etc/passwd%00 did not included
–
Smile.HunterJul 21 '12 at 18:33

I have no idea why the LFI param is that way, it doesn't even make sense to have it that way. Removing the /./././... etc., should work perfectly, so without actually looking at the specific issue at hand, I wouldn't be able to give you a good answer.
–
Karthik RangarajanJul 22 '12 at 7:30