php directory traversal issue - php

Hi
We have some php code using the file_get_contents() function, and I understand this is vulnerable to direcoty traversel attacks. Given the following code:
$mydata=$_GET['thefile'];
$data = file_get_contents ('/var/html'.$file);
echo $data
How can I do some simple input filtering so I can block the posibility that someone might do directory traversel by playing around with my input?
/MR

You want basename:
$mydata = basename(realpath($_GET['thefile']));
Appended to (slight modifications of) your example:
$file=$_GET['thefile'];
$mypath='/var/www/';
$location= basename(realpath($mypath.$file));
$data = file_get_contents($location);
echo $data;
Note... although this does some level of error checking, it does no error handling. I'll leave that up to you.

If the $_GET['thefile'] won't use folders like "images/fileX.jpg" you can use basename()
$filename = basename($_GET['thefile']);
readfile('/var/html/'.$filename);
When '../../passwords.txt' is given as $_GET['thefile'] it will be converted by basename to 'passwords.txt'.
Adding realpath() inside a basename doesn't add any security.
If your script does need to support subdirectories then use realpath() to determine if it's inside the '/var/html' directory.
$baseDir = realpath('/var/html/'); // (mayby /var/html is a symlink)
$baseDirLength = strlen($baseDir);
$filepath = realpath('/var/html/'.$_GET['thefile']);
if (substr($filepath, 0, $baseDirLength) == $baseDir) {
// Even when all the '../' in the thefile are resolved
// the path is within the $baseDir
} else {
// invalid $_GET['thefile']
}

Related

PHP - Function to read and write a TXT file

I'm making a function on WordPress to get the content of the robots.txt file. If the file doesn't exist, create it with default content. I will use it for my options page. Well, this is my code, it should work almost creating the file, but it doesn't:
function get_robots($robots_file) {
$robots_file = get_home_path() . 'robots.txt'; //The robots file.
$dir = get_home_path(); //The root directory
if(is_file($robots_file)){
$handle = fopen($robots_file, "r");
$robots_content = fread($handle, filesize($robots_file));
fclose($handle);
} else {
$default_content = "User-agent: *\nDisallow:";
chmod($dir, 0777);
$handle = fopen($robots_file, "w+");
$robots_content = fwrite($handle, $default_content);
fclose($handle);
}
chmod($dir, 0744);
return $robots_content;
}
I'm not sure if the problem is is_file, or the fopen($robots_file, "w+" (should it be "r"?) after the else. And I'm not sure about the permissions. Is the 777 needed? Is the 744 the default for the root directory of WordPress?
And I use the return to use it as variable later; I suppose the fopen is already creating the file. Am I right?
Thanks in advance.
The first thing, I would use completely different functions, you have file_put_contents() and file_get_contents() for such simple operations.
So possible simpler solution is:
function get_robots() {
$robots_file = get_home_path() . 'robots.txt'; //The robots file.
if(file_exists($robots_file)){
return file_get_contents($robots_file);
} else {
$default_content = "User-agent: *\nDisallow:";
file_put_contents($robots_file, $default_content);
return $default_content;
}
}
I don't see any point to pass $robots_file as function argument so I removed it. You should check if this code simple works.
I also don't see any reason to change $dir permissions as you showed in your code. It should be rather set manually and you definitely shouldn't change your root directory permission in such function.
EDIT
Because this function uses get_home_path() and this one is available probably only on admin panel you have to do it in different way. You may add the following code to the end of your index.php file:
function get_robots($path)
{
$robots_file = $path . DIRECTORY_SEPARATOR . 'robots.txt'; //The robots file.
if(file_exists($robots_file)){
return file_get_contents($robots_file);
} else {
$default_content = "User-agent: *\nDisallow:";
file_put_contents($robots_file, $default_content);
return $default_content;
}
}
get_robots(getcwd());
(Of course if you want, you may move get_robots() function to some other files.
However you should consider if this is the best approach. You will run this function each time your site will be viewed and it's tiny waste (in fact you will probably want to create robots.txt file just once). You could for example create robots.php file and if you want to run it you can run http://yourwordpressurl/robots.php. It's of course your call.

php mkdir folder tree from array

I'm trying to create a folder tree from an array, taken from a string.
$folders = str_split(564);
564 can actually be any number. The goal is to create a folder structure like /5/6/4
I've managed to create all folders in a single location, using code inspired from another thread -
for ($i=0;$i<count($folders);$i++) {
for ($j=0;$j<count($folders[$i]);$j++) {
$path .= $folders[$i][$j] . "/";
mkdir("$path");
}
unset($path);
}
but this way I get all folders in the same containing path.
Furthermore, how can I create these folders in a specific location on disk? Not that familiar with advanced php, sorry :(
Thank you.
This is pretty simple.
Do a for each loop through the folder array and create a string which appends on each loop the next sub-folder:
<?php
$folders = str_split(564);
$pathToCreateFolder = '';
foreach($folders as $folder) {
$pathToCreateFolder .= DIRECTORY_SEPARATOR . $folder;
mkdir($folder);
}
You may also add the base path, where the folders should be created to initial $pathToCreateFolder.
Here you'll find a demo: http://codepad.org/aUerytTd
Or you do it as Michael mentioned in comments, with just one line:
mkdir(implode(DIRECTORY_SEPARATOR, $folders), 0777, TRUE);
The TRUE flag allows mkdir to create folders recursivley. And the implode put the directory parts together like 5/6/4. The DIRECTORY_SEPARATOR is a PHP constant for the slash (/) on unix machines or backslash (\) on windows.
Why not just do:
<?php
$directories = str_split(564);
$path = implode(DIRECTORY_SEPARATOR, $directories);
mkdir($path, 0777, true);
Don't know what you're really trying to do, but here are some hints.
There are recursive mkdir:
if(!file_exists($dir)) // check if directory is not created
{
#mkdir($dir, 0755, true); // create it recursively
}
Path you want can be made in two function calls and prefixed by some start path:
$path = 'some/path/to/cache';
$cache_node_id = 4515;
$path = $path.'/'.join('/', str_split($cache_node_id));
Resulting path can be used to create folder with the code above
So here we come to a pair of functions/methods
function getPath($node_id, $path = 'default_path')
{
return $path.'/'.join('/', str_split($node_id))
}
function createPath($node_id, $path = 'default_path');
{
$path = getPath($node_id, $path);
if(!file_exists($path)) // check if directory is not created
{
#mkdir($path, 0755, true); // create it recursively
}
}
With these you can easily create such folders everywhere you desire and get them by your number.
As mentioned earlier, the solution I got from a friend was
$folders = str_split(564);
mkdir(implode('/',$folders),0777,true);
Also, to add a location defined in a variable, I used
$folders = str_split($idimg);
mkdir($path_defined_earlier. implode('/',$folders),0777,true);
So thanks for all the answers, seems like this was the correct way to handle this.
Now the issue is that I need to the created path, so how can I store it in a variable? Sorry if this breaches any rules, if I need to create a new thread I'll do it...

Check if file exists before displaying in Magento PHP?

I am able to get the web path to the file like so:
$filename = 'elephant.jpg';
$path_to_file = $this->getSkinUrl('manufacturertab');
$full_path = $path_to_file . '/' . $filename;
But if the file doesn't exist, then I end up with a broken image link.
I tried this:
if(!file_exists($full_path)) {
Mage::log('File doesn\'t exist.');
} else {
?><img src="<?php echo $full_path ?>" /><?php
}
Of course that didn't work because file_exists does not work on urls.
How do I solve this?
1.)
Can I translate between system paths and web urls in Magento?
e.g. something like (pseudocode):
$system_path = $this->getSystemPath('manufacturertab');
That looks symmetrical and portable.
or
2.)
Is there some PHP or Magento function for checking remote resource existence? But that seems a waste, since the resource is really local. It would be stupid for PHP to use an http method to check a local file, wouldn't it be?
Solution I am currently using:
$system_path = Mage::getBaseDir('skin') . '/frontend/default/mytheme/manufacturertab'; // portable, but not pretty
$file_path = $system_path . '/' . $filename;
I then check if file_exists and if it does, I display the img. But I don't like the asymmetry between having to hard-code part of the path for the system path, and using a method for the url path. It would be nice to have a method for both.
Function
$localPath = Mage::getSingleton( 'core/design_package' )->getFilename( 'manufacturertab/' . $filename, array( '_type' => 'skin', '_default' => false ) );
will return the same path as
$urlPath = $this->getSkinUrl( 'manufacturertab/' . $filename );
but on your local file system. You can omit the '_default' => false parameter and it will stil work (I left it there just because getSkinUrl also sets it internaly).
Note that the parameter for getSkinUrl and getFilename can be either a file or a directory but you should always use the entire path (with file name) so that the fallback mechanism will work correctly.
Consider the situation
skin/default/default/manufacturertab/a.jpg
skin/yourtheme/default/manufacturertab/b.jpg
In this case the call to getSkinUrl or getFilename would return the path to a.jpg and b.jpg in both cases if file name is provided as a parameter but for your case where you only set the folder name it would return skin/yourtheme/default/manufacturertab/ for both cases and when you would attach the file name and check for a.jpg the check would fail. That's why you shold always provide the entire path as the parameter.
You will still have to use your own function to check if the file exists as getFilename function returns default path if file doesn't exist (returns skin/default/default/manufacturertab/foo.jpg if manufacturertab/foo.jpg doesn't exist).
it help me:
$url = getimagesize($imagepath); //print_r($url); returns an array
if (!is_array($url))
{
//if file does not exists
$imagepath=Mage::getDesign()->getSkinUrl('default path to image');
}
$fileUrl = $this->getSkinUrl('images/elephant.jpg');
$filePath = str_replace( Mage::getBaseUrl(), Mage::getBaseDir() . '/', $fileUrl);
if (file_exists($filePath)) {
// display image ($fileUrl)
}
you can use
$thumb_image = file_get_contents($full_path) //if full path is url
//then check for empty
if (#$http_response_header == NULL) {
// run check
}
you can also use curl or try this link http://junal.wordpress.com/2008/07/22/checking-if-an-image-url-exist/
Mage::getBaseDir() is what you're asking for. For your scenario, getSkinBaseDir() will perform a better job.
$filename = 'elephant.jpg';
$full_path = Mage::getDesign()->getSkinBaseDir().'/manufacturertab/'.$filename;
$full_URL=$this->getSkinUrl('manufacturertab/').$filename;
if(!is_file($full_path)) {
Mage::log('File doesn\'t exist.');
} else {
?><img src="<?php echo $full_URL ?>" /><?php
}
Note that for the <img src> you'll need the URL, not the system path. ...
is_file(), rather than file_exists(), in this case, might be a good option if you're sure you're checking a file, not a dir.
You could use the following:
$file = 'http://mysite.co.za/files/image.jpg';
$file_exists = (#fopen($file, "r")) ? true : false;
Worked for me when trying to check if an image exists on the URL

What PHP function(s) should I use to cut off the end of a string?

I have a filename stored with the directory as a value.
Ex. /var/www/remove_this.php
In my PHP script I want to remove everthing after the last '/', so I can use mkdir on this path without creating a directory from the filename also.
There are so many string editing functions, I don't know a good approach. Thanks!
dirname() will return you the directory part of the path
Use pathinfo() to get info about the file itself.
$file = '/var/www/remove_this.php';
$pathinfo = pathinfo($file);
$dir = $pathinfo['dirname']; // '/var/www/'
You could use string functions, but for this case PHP has some smarter directory functions:
$dir = dirname('/var/www/remove_this.php'); // /var/www
pathinfo is an excellent one as well.
<?php
$file="/var/www/remove_this.php";
$folder=dirname($var);
if (!file_exsts($folder))
{
if (mkdir($folder,777,true))
{
echo "Folder created\n";
} else
{
echo "Folder creation failed\n";
}
} else
{
echo "Folder exists already\n";
}
?>

PHP's file_exists() will not work for me?

For some reason this PHP code below will not work, I can not figure it out.
It is very strange,
file_exists does not seem to see that the image does exist, I have checked to make sure a good file path is being inserted into the file_exists function and it is still acting up
If I change file_exists to !file_exists it will return an images that exist and ones that do not exist
define('SITE_PATH2', 'http://localhost/');
$noimg = SITE_PATH2. 'images/userphoto/noimagesmall.jpg';
$thumb_name = 'http://localhost/images/userphoto/1/2/2/59874a886a0356abc1_thumb9.jpg';
if (file_exists($thumb_name)) {
$img_name = $thumb_name;
}else{
$img_name = $noimg;
}
echo $img_name;
file_exists() needs to use a file path on the hard drive, not a URL. So you should have something more like:
$thumb_name = $_SERVER['DOCUMENT_ROOT'] . 'images/userphoto/1/2/2/59874a886a0356abc1_thumb9.jpg';
if(file_exists($thumb_name)) {
some_code
}
http://us2.php.net/file_exists
docs say:
As of PHP 5.0.0, this function can also be used with some URL wrappers. Refer to List of Supported Protocols/Wrappers for a listing of which wrappers support stat() family of functionality.
file_exists does only work on the local file system.
So try this if you’re using localhost:
$thumb_name = 'images/userphoto/1/2/2/59874a886a0356abc1_thumb9.jpg';
if (file_exists($_SERVER['DOCUMENT_ROOT'].$thumb_name)) {
$img_name = SITE_PATH2.$thumb_name;
} else {
$img_name = $noimg;
}
Have you enabled the option which allows you to use external URLs? You can set it in php.ini:
allow_url_fopen = 1
You have to write the file path like "file:///C:/Documents%20and%20Settings/xyz/Desktop/clip_image001.jpg".
http://php.net/manual/en/function.file-exists.php
did you check the comments below?
Just reading parts of it, but there seem to be several issues.
Caching may be a problem.
When opening FTP urls it always returns true (they say in the comments)
...
Try Below one. Its working for me
define('SITE_PATH2', 'http://localhost/');
$noimg = SITE_PATH2. 'images/userphoto/noimagesmall.jpg';
$thumb_name = 'http://localhost/images/userphoto/1/2/2/59874a886a0356abc1_thumb9.jpg';
if ($fileopen = #fopen($thumb_name)) {
$img_name = $thumb_name;
fclose($fileopen);
}else{
$img_name = $noimg;
}
echo $img_name;

Categories