mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 00:46:50 +02:00
MDL-15716 Tightened dataroot security checks and and 'loud' administrator warning
This commit is contained in:
parent
bd2bf45169
commit
bba0beaee2
9 changed files with 142 additions and 10 deletions
108
lib/adminlib.php
108
lib/adminlib.php
|
@ -31,6 +31,8 @@ global $upgradeloghandle, $upgradelogbuffer;
|
|||
$upgradeloghandle = false;
|
||||
$upgradelogbuffer = '';
|
||||
|
||||
define('INSECURE_DATAROOT_WARNING', 1);
|
||||
define('INSECURE_DATAROOT_ERROR', 2);
|
||||
|
||||
/**
|
||||
* Upgrade savepoint, marks end of each upgrade block.
|
||||
|
@ -985,13 +987,38 @@ function upgrade_log_callback($string) {
|
|||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if and critical warnings are present
|
||||
* @return bool
|
||||
*/
|
||||
function admin_critical_warnings_present() {
|
||||
global $SESSION;
|
||||
|
||||
if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!isset($SESSION->admin_critical_warning)) {
|
||||
$SESSION->admin_critical_warning = 0;
|
||||
if (ini_get_bool('register_globals')) {
|
||||
$SESSION->admin_critical_warning = 1;
|
||||
} else if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
|
||||
$SESSION->admin_critical_warning = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $SESSION->admin_critical_warning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to verify that dataroot is not accessible from web.
|
||||
* It is not 100% correct but might help to reduce number of vulnerable sites.
|
||||
*
|
||||
* Protection from httpd.conf and .htaccess is not detected properly.
|
||||
* @param bool $fetchtest try to test public access by fetching file
|
||||
* @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING migth be problematic
|
||||
*/
|
||||
function is_dataroot_insecure() {
|
||||
function is_dataroot_insecure($fetchtest=false) {
|
||||
global $CFG;
|
||||
|
||||
$siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
|
||||
|
@ -1010,10 +1037,83 @@ function is_dataroot_insecure() {
|
|||
$siteroot = strrev($siteroot);
|
||||
$dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
|
||||
|
||||
if (strpos($dataroot, $siteroot) === 0) {
|
||||
return true;
|
||||
if (strpos($dataroot, $siteroot) !== 0) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
if (!$fetchtest) {
|
||||
return INSECURE_DATAROOT_WARNING;
|
||||
}
|
||||
|
||||
// now try all methods to fetch a test file using http protocol
|
||||
|
||||
$httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
|
||||
preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
|
||||
$httpdocroot = $matches[1];
|
||||
$datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
|
||||
if (make_upload_directory('diag', false) === false) {
|
||||
return INSECURE_DATAROOT_WARNING;
|
||||
}
|
||||
$testfile = $CFG->dataroot.'/diag/public.txt';
|
||||
if (!file_exists($testfile)) {
|
||||
file_put_contents($testfile, 'test file, do not delete');
|
||||
}
|
||||
$teststr = trim(file_get_contents($testfile));
|
||||
if (empty($teststr)) {
|
||||
// hmm, strange
|
||||
return INSECURE_DATAROOT_WARNING;
|
||||
}
|
||||
|
||||
$testurl = $datarooturl.'/diag/public.txt';
|
||||
|
||||
if (extension_loaded('curl') and ($ch = @curl_init($testurl)) !== false) {
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
$data = curl_exec($ch);
|
||||
if (!curl_errno($ch)) {
|
||||
$data = trim($data);
|
||||
if ($data === $teststr) {
|
||||
curl_close($ch);
|
||||
return INSECURE_DATAROOT_ERROR;
|
||||
}
|
||||
}
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
if ($data = @file_get_contents($testurl)) {
|
||||
$data = trim($data);
|
||||
if ($data === $teststr) {
|
||||
return INSECURE_DATAROOT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
preg_match('|https?://([^/]+)|i', $testurl, $matches);
|
||||
$sitename = $matches[1];
|
||||
$error = 0;
|
||||
if ($fp = @fsockopen($sitename, 80, $error)) {
|
||||
preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
|
||||
$localurl = $matches[1];
|
||||
$out = "GET $localurl HTTP/1.1\r\n";
|
||||
$out .= "Host: $sitename\r\n";
|
||||
$out .= "Connection: Close\r\n\r\n";
|
||||
fwrite($fp, $out);
|
||||
$data = '';
|
||||
$incoming = false;
|
||||
while (!feof($fp)) {
|
||||
if ($incoming) {
|
||||
$data .= fgets($fp, 1024);
|
||||
} else if (@fgets($fp, 1024) === "\r\n") {
|
||||
$incoming = true;
|
||||
}
|
||||
}
|
||||
fclose($fp);
|
||||
$data = trim($data);
|
||||
if ($data === $teststr) {
|
||||
return INSECURE_DATAROOT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return INSECURE_DATAROOT_WARNING;
|
||||
}
|
||||
|
||||
/// =============================================================================================================
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue