Blog post

SuiteCRM 7.11.4 - Breaking Into Your Internal Network

Robin Peraglie photo

Robin Peraglie

Vulnerability Researcher

6 min read

  • Security

SuiteCRM, a customer relationship software, is a great first economic choice as CRM software because it is free and open source. However, in this blog post we will see how a vulnerable web application deployed in the internal network of your company can act as a charming entry gateway for any adversary. As part of our efforts to make the open source web application space more secure we analyzed SuiteCRM 7.11.4 and detected multiple critical vulnerabilities. Among them is a SQL Injection that can be exploited as a normal user (CVE-2019-12598), which can be leveraged into a multi-step PHP Object Injection leading to a Remote Code Execution (CVE-2019-12601) giving an attacker full control of the underlying server. The cherry on top of the cake: an attacker can exploit this vulnerability without any valid login credentials and without direct access to the internal network.

Hacking into your Network: Arbitrary Database Write via CSRF

The SuiteCRM web application is vulnerable to a SQL Injection which is present in the WizardNewsletterSave action of the Campaigns module. To exploit this vulnerability, the attacker can make use of a Spear Phishing attack to lure a faithful and benign employee who is logged into the company’s web application into visiting/clicking a malicious and evil website (e.g. http://evilattacker.com). The website will embed an image which is pointing to a specially crafted malicious URL, causing the browser to issue a HTTP request to the following target:


http://<internal-network-suitecrm>/index.php?module=Campaigns&action=WizardNewsletterSave&currentstep=1&wiz_step1_field_defs[SOMEFIELD​][default]=​SOMEVALUE​&wiz_step1_table_name=​SOMETABLENAME​&wiz_step1_id=1337&wiz_step1_new_with_id=1


If the browser of the victim - authenticated to the SuiteCRM web application - issues a HTTP request to this link then the following SQL query is executed on the underlying database:

INSERT INTO​    SOMETABLENAME​  ( SOMEFIELD​ )   VALUES​ ( 'SOMEVALUE'​ ) 

The root cause of this problem originates in the WizardNewsletterSave.php file of the application logic which is populating the instance of a SugarBean object from the HTTP request sent by the attacker. As seen in line 70 of the following source code, this is done before saving the SugarBean to the database.


modules/Campaigns/WizardNewsletterSave.php

69    <?php foreach ( $camp_steps as $step​ )
70    $campaign_focus=populate_wizard_bean_from_request​($campaign_focus​, $step​);
71    …
72    $campaign_focus​->​save​();

However, the function populate_wizard_bean_from_request() allows an attacker to set the object properties of the constructed bean arbitrarily, which is known as Variable Tampering. Such a vulnerability can be observed in line 409 and 410 where user input$_REQUEST[$key] is assigned to the dynamic $field property of the object which was built from the attacker controlled parameter name $key.


modules/Campaigns/WizardNewsletterSave.php

402    function populate_wizard_bean_from_request​($bean​, $prefix​)
403    {
404        foreach($_REQUEST ​as $key​ => $val​) {
405            $key = trim​($key​);
406            if((strstr​($key​, $prefix​)) && (strpos​($key​, $prefix​) == 0)) {
407                $field = substr​($key, strlen​($prefix​));
408                if(isset​($_REQUEST​[$key​]) && !empty​($_REQUEST​[$key​])) {
409                    $value = $_REQUEST​[$key​];
410                    $bean​->​$field = $value​;
411                }
412            }
413        }
414        return $bean​;
415    }

Especially the table_name property of a SugarBean instance is prone to be written by the attacker because it is directly embedded into a SQL query. The property is returned by the getTableName() method on line 1964 and spared by further sanitization leading to the SQL Injection.


modules/Campaigns/WizardNewsletterSave.php

1962    public function insertSQL(SugarBean $bean)
1963    {
1964        $sql = $this->insertParams($bean->getTableName(), /…/);
1965        return $sql;

This feature allows any adversary to inject malicious entries into the database of the server which has critical effects standalone: an attacker can create a secondary administrator account next to removing and inserting arbitrary information. Since a CRM software is usually isolated in the internal network, this vulnerability alone is hardly exploitable. However, in the following section we will see how this SQL Injection can be leveraged into a Remote Code Execution vulnerability easily by chaining together multiple exploits.

Remote Code Execution on the Internal Network Server

We detected that database write access to the stored_options column of the inbound_email table can be leveraged into an advanced Multi Step PHP Object Injection vulnerability which leads to a Remote Code Execution. To achieve this goal, an attacker needs to insert a row with a known id (e.g. 313373​) into the inbound_emailtable of the database connected to the SuiteCRM web application containing a base64 encoded version of a serialized malicious PHP object. The specially crafted PHP object will hijack the control flow of the underlying application logic to spawn a malicious shell.php file in the root directory of SuiteCRM, as soon as the object is deserialized.


http://<SuiteCRM7114Host>/index.php?module=Emails&action=EmailUIAjax&emailUIAction=sendEmail&fromAccount=313373


By embedding a second image and sending another request to the web application, the payload is read from the database, deserialized and executed. As a result, the attacker can execute code on the freshly hijacked internal network server.


The issue is located in the getInboundMailerSettings​() method where the stored serialized payload is retrieved and deserialized on demand. The issued HTTP request will directly cause the web application to load the options stored under the id (e.g 313373) which have been overwritten previously.


include/OutboundEmail/OutboundEmail.php

338    public function getInboundMailerSettings​($user​, $mailer_id=''​, $ieId=''​)
339    {
340        /…/
341        if (!empty​($mailer_id​)) {
342            /…/
343        } elseif (!empty​($ieId​)) {
344            $q = "SELECT stored_options FROM inbound_email WHERE id = '​{$ieId}'"​;
345            $r = $this​->​db​->​query( $q​ );
346            $a = $this​->​db->fetchByAssoc​( $r​ );
347            if (!empty​ ( $a​ )) {
348                $opts = unserialize​(base64_decode​($a​['stored_options'​]));

If you want to know more on how to exploit a PHP Object Injection like this into Remote Code Execution read more about it in our blog post.

Timetable

DateWhat
17/May/19First contact with vendor
17/May/19Response of vendor
20/May/19Vendor informs about release plans for fix
03/June/19Fixed with version 7.11.5 and SuiteCRM LTS 7.10.17

Summary

Isolating a vulnerable web application into your internal network does not guard it from external attackers, in fact, it can be used as an entry gateway for any attacker through a sophisticated combination of Spear Phishing, Cross Site Request Forgery and an attacking technique which suites the vulnerable web application. At the end of the day, any web application deployed in your network should implement sufficient security, either assured through tedious manual security testing or with time efficient automated security tools. If you are running SuiteCRM please update as soon as possible to the latest release of SuiteCRM.