Wouldn't web application penetration testing be easier if you could look at the source code? Well, when looking to expand my web app pen testing skills, my good friend and co-worker, Josh Wright, mentioned a specific new twist for Local File Include vulnerabilities on PHP-based web servers: PHP wrappers.
PHP wrappers allow us to make Local File Includes far more useful. The PHP interpreter can handle many things as streams of data, such as local files, remote URL's, and even remote SSH systems! What's most interesting today, though, is accessing "various I/O streams" through the php:// wrapper. With php://, we can read the Standard Input, Standard Output, and Standard Error of the PHP interpreter itself. For example, with php://stdin, we can read the raw input a user sends, which can be useful if the PHP interpreter adds some formatting and such that can get in our way. This often comes up with JSON being sent to a PHP interpreter, for example.
The most interesting wrapper, though, is the most meta of them all — the php://filter wrapper, which allows us to apply one or more file transforms to a file input or output. What kinds of filters, you ask? All sorts of kinds, I reply!
$ php -a Interactive mode enabled php > $streamlist = stream_get_filters(); php > print_r($streamlist); Array ( [0] => zlib.* [1] => string.rot13 [2] => string.toupper [3] => string.tolower [4] => string.strip_tags [5] => convert.* [6] => consumed [7] => dechunk [8] => convert.iconv.* )
Honestly, I'm not sure why I'd need to do ROT13 on a stream of text as part of a real application, but it's not nearly as interesting as the filters underneath item #4, convert — specifically convert.base64-encode. How do we make it work? The syntax is a bit odd, but luckily a pre-canned line will do for 99% of cases:
$ echo "Something secret" > secret.txt $ php -a php > include("php://filter/base64-encode/resource=secret.txt"); Something secret
Good point, Philosoraptor! In this example, I could've just as well done this:
php > include("secret.txt"); Something secretSomething secret
So why use php://filter at all? Well, oftentimes a file extension is added on the server-side code as follows:
<?php include($_GET["page"] . ".php"); ?>
And imagine I have another page, index.php, that looks like this:
<?php print("Some index page or something\n"); ?>
You've probably seen URL's like the following: http://localhost/ex1.php?page=index. That URL will load index.php (the ".php" is added server-side, remember) and include it in the HTTP response as follows:
$ curl "http://localhost/ex1.php?page=index" Some index page or something
However, we can't see the source to either ex1.php or index.php, because the PHP interpreter will be interpreting that code, not merely displaying it. With the magic of the base64-encode PHP filter, though, the PHP interpreter will not interpret the resource as code. This allows us to see the original server-side PHP code content! Let's give it a shot:
$ curl -s "http://localhost/ex1.php?page=php://filter/convert.base64-encode/resource=index" PD9waHAKcHJpbnQoIlNvbWUgaW5kZXggcGFnZSBvciBzb21ldGhpbmdcbiIpOwo/Pgo= $ curl -s "http://localhost/ex1.php?page=php://filter/convert.base64-encode/resource=index" | base64 -d <?php print("Some index page or something\n"); ?>
Great! The ".php" extension is still added on the server side, but we've managed to get something very useful anyway. Now we can examine the PHP for SQL injection, code injection, secrets like database connection information, etc.
Have fun hacking all the things!