During our vulnerability research on the largest CMS systems we came across CiviCRM last year. It’s an open source CRM plugin for the most popular CMS systems like Wordpress, Joomla, Drupal, and Backdrop. CiviCRM is specifically designed for the needs of non-profit, non-governmental, and advocacy groups, and serves as an association management system. According to CiviCRM, it has been used by more than 11,000 organizations, processed more than 116 million donations, and managed 189 million contacts which makes it an attractive target for cyber criminals.
In our analysis we discovered several critical code vulnerabilities in CiviCRM version 5.22.0. A combination of these vulnerabilities allowed remote attackers to execute arbitrary system commands on any CiviCRM instance running on WordPress and to fully compromise the server and its data. In this blog post we analyze the technical root cause of two different security issues and demonstrate how attackers could exploit these. We reported all issues responsibly to the affected vendor who released multiple security patches to protect all users against attacks.
During the analysis of CiviCRM 5.22.0, we found a CSRF vulnerability (CVE-2020-36389) that led to a Stored XSS vulnerability. Both vulnerabilities were fixed in CiviCRM version 5.28.1 and 5.27.5 ESR. Additionally, we discovered a Phar Deserialization vulnerability leading to PHP code execution (CVE-2020-36388). The issue was fixed in CiviCRM version 5.24.3 and 5.21.3.
A combination of all vulnerabilities could allow a remote attacker to execute arbitrary system commands on any CiviCRM instance. As a result, the underlying CMS such as WordPress is compromised too. In order to successfully execute the attack, an authenticated administrator is lured to a malicious page that embeds a form that automatically sends a request to the website, including the administrator's cookies, which allows gaining Remote Code Execution capabilities.
For demonstration purposes we’ve created a short video that shows how quick and easy a server is compromised.
In the following, we look at the root cause of two vulnerabilities in the source code of CiviCRM. First we introduce the stored XSS that can be exploited via CSRF. In the next step, we analyse the root cause of a Phar Deserialization vulnerability.
The administration interface of CiviCRM uses the CKEditor, a rich text editor that enables direct editing and writing of configuration files. Here, a
run() method is used (see code below) that is called each time the editor is accessed. In line 56, the filename of the current config that will be saved is received via
$_REQUEST['present']. In line 63, the
save() method is called with attacker-controlled POST parameters. No CSRF tokens are verified, which results in a CSRF vulnerability (CVE-2020-36389). You can find more details about how CSRF attacks work in our LocalStack blog post.
Let’s have a look at how the content of this file is created. In line 110 in the code below, a default file header is prepended to the configuration file and in lines 113 - 129 the content of the configuration file is composed. Thereby each POST parameter name is processed that starts with
config_ in line 115. The name and value of the POST parameters are concatenated in line 126 and added to the
$config in line 127. In line 130, the
saveConfigFile() method is called with the attacker-controlled variable (
$config) and partially controlled file name (
An attacker can skip lines 115 - 129 by sending a single POST field consisting of the key
config with an arbitrary value, since the key does not start with
Let’s have a look at the name of the file to which this content is written. In line 238 of the following code the filename of the configuration file is composed and in line 239 the content of the file is written. The partial attacker-controlled file name has the following format:
The only attacker controlled information in this filename is
$preset. A path traversal attack is not feasible since a folder
crm-ckeditor- would have to be located above the current directory. Also, the filename would always have the
.js extension which is another limitation.
At first glance, this vulnerability does not seem particularly critical. But from an attacker's point of view, any possibility, no matter how small, is sufficient to carry out an attack. In total, the attacker needs two CSRF requests, where the first CSRF request creates an XSS payload within a config file. The second CSRF request permanently loads the previously dropped XSS config file by overwriting the CKEditor default config.
Using the first CSRF request, the attacker creates a configuration file named
save() method as already mentioned above.
crm-ckeditor-xss.js via a directive which includes the XSS payload. Combining both CSRF requests causes a stored XSS in the entire backend every time the CKEditor is invoked.
However, an administrator does not always have the access privileges to features that allow to control the server, it depends on the configuration of the CMS and the server. Therefore in most cases, attackers try to extend their capabilities, e.g. to execute code on the server. In the following, we introduce another vulnerability that can be used by an attacker to escalate their privileges.
We found this code vulnerability in the Badge component (see code below). In line 22 the user controlled variable
$img from line 21 is passed to the
getImageProperties()method without any further checks.
In line 399 (see code below) the user controlled variable
$img is passed directly to the PHP internal function
getimagesize(), which is vulnerable to Phar Deserialization. Because an attacker can control the entire string, the attacker is able to deserialize objects via the
In order to exploit the Phar Deserialization vulnerability as an attacker, an image must be uploaded to the file system that contains Phar metadata. Then the
getImageProp()method can be called via an Ajax request, whereby the
img parameter points to the path of the previously uploaded image. We found gadgets in the CiviCRM core that allowed us to execute code. This is a strong primitive for an attacker since some CMS systems do not contain any known gadgets. However the vulnerability can only be exploited as an administrator, which is possible via the stored XSS described above.
All in all, the Phar Deserialization leads to code execution in WordPress, other CMS systems like Joomla prevent deserialization of Phar metadata. But from an attacker's point of view, it would be possible to find a universal approach via the stored XSS that would compromise any underlying CMS.
CVE-2020-36389 (CSRF on CKEditor Configuration Form):
This security issue is a classic CSRF vulnerability that can be prevented by adding cryptographically secure tokens that are validated for every sensitive request.
CVE-2020-36388 (PHP Code Execution via Phar Deserialization):
A potential solution is to use a custom Phar wrapper which prevents the untrusted deserialization of Phar metadata. A well-known project for this would be the custom Phar wrapper of Typo3. Moreover, with PHP 8.0 the automatic deserialization from the Phar metadata was disabled. In general, it is advised to always check which user can perform which action within a web application. It is also important to pay attention to third-party features.
|2020-02-18||We report all issues to vendor|
|2020-02-22||Vendor confirmed the issues|
|2020-04-15||Vendor released patch for Phar Deserialization in version 5.24.3 and 5.21.3|
|2020-08-19||Vendor released patch for CSRF and XSS in version 5.28.1 and 5.27.5 ESR|
In this blog post we analyzed two code vulnerabilities found in CiviCRM (5.22.0), a widely used open source solution for customer relationship management written in PHP. The combination of these two vulnerabilities can lead to a complete takeover of a CiviCRM instance. We’ve evaluated the root causes in the PHP code base and described how to fix them. We reported these vulnerabilities to the vendor who confirmed and fixed the vulnerabilities quickly. We would like to thank the CiviCRM team who quickly released multiple patches after our report. If you are hosting a CiviCRM instance and have not yet updated your installation, we highly recommend to do so now.