You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
6.8 KiB
184 lines
6.8 KiB
<?php
|
|
|
|
/* For licensing terms, see /license.txt */
|
|
|
|
/**
|
|
* This script fixes a file-upload vulnerability introduced in Chamilo 1.11.12
|
|
* in a way that cannot be fixed through simple update.
|
|
* It is safe to execute through the web, as it only checks very specific files
|
|
* and directories that should be removed. If permissions do not allow the web
|
|
* server to remove those files, a report will help the user identify which
|
|
* files to remove manually from the server.
|
|
* This refers to Issue 44 described at
|
|
* https://support.chamilo.org/projects/chamilo-18/wiki/Security_issues
|
|
* This script should be run on any Chamilo installation having been updated
|
|
* through Git or through the 1.11.12 installer between early May 2020 and
|
|
* late October 2020.
|
|
*/
|
|
|
|
$deleteList = [
|
|
'js/demo.js',
|
|
'server/',
|
|
'.github/',
|
|
'.gitignore',
|
|
'README.md',
|
|
'SECURITY.md',
|
|
'VULNERABILITIES.md',
|
|
'cors/',
|
|
'docker-composer.yml',
|
|
'test/',
|
|
'wdio/',
|
|
];
|
|
|
|
if (PHP_SAPI != 'cli') {
|
|
if (is_file(__DIR__.'/../../app/config/configuration.php')) {
|
|
require_once __DIR__.'/../../app/config/configuration.php';
|
|
$chamiloFolder = $_configuration['root_sys'];
|
|
} elseif (is_file(__DIR__.'/app/config/configuration.php')) {
|
|
require_once __DIR__.'/app/config/configuration.php';
|
|
$chamiloFolder = __DIR__;
|
|
}
|
|
deleteFilesWeb($chamiloFolder);
|
|
exit;
|
|
}
|
|
// If CLI, do not depend on being inside a Chamilo folder and ask for cli args
|
|
if ($argc < 2) {
|
|
echo "This script scans a main folder where different Chamilo installations might".PHP_EOL."be located and removes files which introduce a security vulnerability.".PHP_EOL;
|
|
echo "It requires 1 or 2 arguments:".PHP_EOL;
|
|
echo " [main path] The main directory where multiple Chamilo installations are located".PHP_EOL;
|
|
echo " [sub path] If each Chamilo directory contains a sub-path ".PHP_EOL;
|
|
echo " (e.g. [main path]/chamilo1/htdocs), give this arguments as \"htdocs\"".PHP_EOL;
|
|
}
|
|
$mainFolder = '/var/www/';
|
|
$subFolder = '/';
|
|
if ($argc == 3) {
|
|
$subFolder = trim($argv[2]);
|
|
if (substr($subFolder, -1, 1) != '/') {
|
|
$subFolder .= '/';
|
|
}
|
|
if (substr($subFolder, 0, 1) != '/') {
|
|
$subFolder = '/'.$subFolder;
|
|
}
|
|
}
|
|
$mainFolder = trim($argv[1]);
|
|
if ('.' == trim($argv[1])) {
|
|
$mainFolder = getcwd().'/';
|
|
} else {
|
|
if (substr($mainFolder, -1, 1) != '/') {
|
|
$mainFolder .= '/';
|
|
}
|
|
}
|
|
|
|
$foldersList = scandir($mainFolder);
|
|
foreach ($foldersList as $folder) {
|
|
// Ignore folders starting with .
|
|
if (substr($folder, 0, 1) == '.') {
|
|
continue;
|
|
}
|
|
$chamiloFolder = $mainFolder.$folder.$subFolder;
|
|
$configPath = $chamiloFolder.'app/config/configuration.php';
|
|
if (file_exists($configPath)) {
|
|
// This is likely Chamilo portal, scan further and delete files
|
|
deleteFilesSystem($chamiloFolder);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete files using PHP
|
|
* @param string $folder The Chamilo root folder
|
|
*/
|
|
function deleteFilesWeb($folder) {
|
|
global $deleteList;
|
|
$dangerFolder = $folder.'app/Resources/public/assets/jquery-file-upload/';
|
|
$dangerFolder2 = $folder.'web/assets/jquery-file-upload/';
|
|
echo "Analyzing Chamilo folder...<br />".PHP_EOL;
|
|
$risk = 0;
|
|
if (file_exists($dangerFolder)) {
|
|
$risk = 1;
|
|
echo " Dangerous folder 1 exists in Resources, cleaning...<br/>".PHP_EOL;
|
|
foreach ($deleteList as $deleteEntry) {
|
|
if (substr($deleteEntry, -1, 1) == '/') {
|
|
// this is a folder, recurse
|
|
rmdirr($dangerFolder.$deleteEntry);
|
|
} else {
|
|
unlink($dangerFolder.$deleteEntry);
|
|
}
|
|
}
|
|
if (is_file($dangerFolder.'README.md')) {
|
|
echo "There was a problem removing files in 'app/Resources/public/assets/jquery-file-upload/'. Please remove the following files and folders manually:<br />".PHP_EOL;
|
|
echo "<ul>".PHP_EOL;
|
|
foreach ($deleteList as $deleteEntry) {
|
|
echo "<li>[chamilo folder]/app/Resources/public/assets/jquery-file-upload/".$deleteEntry."</li>".PHP_EOL;
|
|
}
|
|
echo "</ul>".PHP_EOL;
|
|
}
|
|
}
|
|
if (file_exists($dangerFolder2)) {
|
|
$risk = 1;
|
|
echo " Dangerous folder 2 exists in web, cleaning...<br />".PHP_EOL;
|
|
foreach ($deleteList as $deleteEntry) {
|
|
if (substr($deleteEntry, -1, 1) == '/') {
|
|
// this is a folder, recurse
|
|
rmdirr($dangerFolder2.$deleteEntry);
|
|
} else {
|
|
unlink($dangerFolder2.$deleteEntry);
|
|
}
|
|
}
|
|
if (is_file($dangerFolder2.'README.md')) {
|
|
echo "There was a problem removing files in 'web/assets/jquery-file-upload/'. Please remove the following files and folders manually:<br />".PHP_EOL;
|
|
echo "<ul>".PHP_EOL;
|
|
foreach ($deleteList as $deleteEntry) {
|
|
echo "<li>[chamilo folder]/web/assets/jquery-file-upload/".$deleteEntry."</li>".PHP_EOL;
|
|
}
|
|
echo "</ul>".PHP_EOL;
|
|
}
|
|
}
|
|
if ($risk == 0) {
|
|
echo "No dangerous file could be found. Your installation looks safe.<br />".PHP_EOL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete files from the command line
|
|
* @param string $folder The Chamilo root folder
|
|
*/
|
|
function deleteFilesSystem($folder) {
|
|
global $deleteList;
|
|
$dangerFolder = $folder.'app/Resources/public/assets/jquery-file-upload/';
|
|
$dangerFolder2 = $folder.'web/assets/jquery-file-upload/';
|
|
echo "Analyzing folder $folder...".PHP_EOL;
|
|
if (is_dir($dangerFolder.'server/')) {
|
|
echo " Found $dangerFolder"."server/, cleaning...".PHP_EOL;
|
|
foreach ($deleteList as $deleteEntry) {
|
|
$recurse = '';
|
|
if (substr($deleteEntry, -1, 1) == '/') {
|
|
// this is a folder, recurse
|
|
$recurse = '-r';
|
|
}
|
|
if (file_exists($dangerFolder.$deleteEntry)) {
|
|
$return = system('rm '.$recurse.' '.$dangerFolder.$deleteEntry);
|
|
if ($return === false) {
|
|
echo " $dangerFolder$deleteEntry could not be deleted. Please delete manually.".PHP_EOL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (is_dir($dangerFolder2.'server/')) {
|
|
echo " Found $dangerFolder2"."server/, deleting...".PHP_EOL;
|
|
foreach ($deleteList as $deleteEntry) {
|
|
$recurse = '';
|
|
if (substr($deleteEntry, -1, 1) == '/') {
|
|
// this is a folder, recurse
|
|
$recurse = '-r';
|
|
}
|
|
if (file_exists($dangerFolder2.$deleteEntry)) {
|
|
$return = system('rm '.$recurse.' '.$dangerFolder2.$deleteEntry);
|
|
if ($return === false) {
|
|
echo " $dangerFolder2$deleteEntry could not be deleted. Please delete manually.".PHP_EOL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
echo " Done with $folder".PHP_EOL;
|
|
}
|
|
|
|
|