So there I was exploiting a LFI, only problem being I hit a brick wall. I did not see any possible way to leverage my LFI so that I could get RCE or even leverage it in such a way that I would be able to view the source of other PHP files. Now WTF should I do I asked myself?
First of all let me explain the problems I encountered and why I wasn’t able to leverage the LFI:
- I could not read any file in the directories /etc/ & /var/
- No remote URL’s where allowed
- No file upload possibility
- No email possibility
- No access to the apache logs
- No access to /proc/self/environ
- Seemed to be running mod_security
Of course I also played with encoding the payloads in various ways to try and avoid possible pattern detection schemes. None of this paid off, I spend a some time trying to bypass the limitation I had encountered but without any luck. So I decided to ask for some help on IRC, luckily some people(thank you hdm & darkfig) also decided to help me out and they pointed me into a new direction. They proposed I looked into using my own HTTP POST payload as an possible attack vector to leverage RCE. So how does this attack work(References for everything in this post will be given at the end of the post)?
Using PHP Protocol Wrappers you tell PHP to use the HTTP POST data as the entry point for it’s include. For example:
Then you can for example include the following code snippet in the POST data:
<?php phpinfo(); ?>
According to the PHP documentation it allows you to read raw post data:
php://input allows you to read raw POST data. It is a less memory intensive alternative to $HTTP_RAW_POST_DATA and does not need any special php.ini directives. php://input is not available with enctype=”multipart/form-data”.
Now that was EXCELLENT NEWS!!! So I decided to test this all in a test environment. I booted up Ubuntu and did a
sudo apt-get install libapache2-mod-php5
I’m lazy and that will install all dependencies. After it all installed I went ahead and tested the method.
It didn’t work :( AARGH!!!
Now that sucked, after changing the configuration I got it to work, but well that sucks in a normal environment you can’t just change the PHP configuration on your target.
allow_url_include = On
Does NOT work:
allow_url_include = Off
Now that’s a bummer, still it’s a nice trick to have up your sleeve and a pretty darn good reminder to myself: ALWAYS think outside the box! Good thing IRC still exists and that it has nice people on it like hdm and darkfig who help people like me out.
So I could have stopped and given up…then again that would mean ignoring the reminder I just got about thinking outside the box. I decided to go ahead and see if I could maybe abuse any of the PHP features to at least view some sourcecode of local PHP files. So I started to play around with the PHP filter wrapper, since according to the documentation the other ones like memory/temp/input where protected by allow_url_include. An excerpt from the documentation:
php://filter is a kind of meta-wrapper designed to permit the application of filters to a stream at the time of opening. This is useful with all-in-one file functions such as readfile(), file(), and file_get_contents() where there is otherwise no opportunity to apply a filter to the stream prior the contents being read.
So if I understand this correctly it means that I can alter the stream content BEFORE the calling function gets to work with it. Now that’s fun, so after some toying around with it and figuring out stuff(which filters it supports and such), the following command can be used to get the source of the PHP files on the server.
The output from the above URL is the base64 encoded content of the in.php file. YEAH BABY! Now I can go hunt for bugs in other PHP files available on the server.
Here are the references I used while researching this:
- The POST DATA method
- PHP Protocol Wrappers documentation
- PHP Filter documentation
I would say this is a nice example of how to abuse intended features for your own fun and profit.
p.s Don’t forget this is also a very nice way to download binary files, since they first get base64 encoded.