RIPS Analysis

The e107 CMS consists of 317,356 lines of code and was analyzed in about 2 minutes. Many of the vulnerabilities found by RIPS are exploitable, despite a few exceptions. The main reason for this is that e107 contains a lot of unused code from previous releases and thus not all affected functions are reachable. Most of the SQL injection vulnerabilities are caused by missing quotes. The input gets escaped properly, but since it is not surrounded by quotes this is not sufficient and the SQL query can be modified.

The truncated analysis results are available in our RIPS demo application. Please note that we limited the results to the issues described in this post in order to ensure a fix is available.

Case Study

PHP Object Injection to Privilege Escalation

e107 suffers from a PHP Object Injection vulnerability, i.e. user input is passed to the function unserialize(). The MD5 sum of the user input is checked in line 354, but there is no secret involved and thus an attacker can simply calculate the value himself. The correct approach would have been to use a keyed-hash message authentication code (HMAC) to prevent modifications by malicious users that do not possess the secret key.

usersettings.php

353
354
355
356
357
$new_data = base64_decode($_POST['updated_data']);
if (md5($new_data) != $_POST['updated_key'] || ($userMethods->hasReadonlyField($new_data) !== false)) {
    exit();
}
$changedUserData = unserialize($new_data);

Unlike in our Expression Engine post, an attacker does not have to use property oriented programming to reach sensitive code that can be exploited. The return value of unserialize() is stored in the variable $changedUserData that is then used directly in further sensitive operations.

usersettings.php

453
454
455
$changedData['data'] = $changedUserData;
$changedData['WHERE'] = 'user_id='.$inp;
if (FALSE === $sql->update('user', $changedData))

e107_handlers/mysql_class.php

1160
1161
1162
1163
1164
function update($tableName, $arg, $debug = FALSE, $log_type = '', $log_remark = '') {
    $table = $this->db_IsLang($tableName);
    $arg = $this->_prepareUpdateArg($tableName, $arg);
    $query = 'UPDATE '.$this->mySQLPrefix.$table.' SET '.$arg;
    $result = $this->mySQLresult = $this->db_Query($query, NULL, 'db_Update');

Namely, the data is used in a SQL UPDATE query. This query is build by using the _prepareUpdateArg() method.

e107_handlers/mysql_class.php

1083
1084
1085
1086
1087
1088
1089
1090
1091
private function _prepareUpdateArg($tableName, $arg) {
    
    foreach ($arg['data'] as $fn => $fv) {
        $new_data .= ($new_data ? ', ' : '');
        $ftype = isset($fieldTypes[$fn]) ? $fieldTypes[$fn] : 'str';
        $new_data .= "{$fn}=".$this->_getFieldValue($fn, $fv, $fieldTypes);
        
    }
    return $new_data .(isset($arg['WHERE']) ? ' WHERE '. $arg['WHERE'] : '');

1247
1248
1249
1250
1251
1252
function _getFieldValue($fieldKey, $fieldValue, &$fieldTypes) {
    $type = isset($fieldTypes[$fieldKey]) ? $fieldTypes[$fieldKey] : $fieldTypes['_DEFAULT'];
    switch ($type) {
        case 'str':
        case 'string':
            return "'".$this->escape($fieldValue, false)."'";

All values are escaped by _getFieldValue() in line 1088 of the method _prepareUpdateArg(). However, with the help of the object injection, an attacker is able to specify arbitrary array keys and those are not sanitized in any way. This allows the attacker to modify the UPDATE query that is performed on the user table and to set arbitrary values. It is possible to change permissions of accounts, set new passwords, read information from other tables, and to inject JavaScript in the database for persistent cross-site scripting attacks. In short, the attacker has full control over the application.

Time Line

Date What
2016/11/18 First contact with vendor
2016/11/21 Send details to vendor
2016/11/27 Vendor pushes fix for most critical vulnerabilities to repository
2016/11/29 Vendor starts patching the less-severe vulnerabilities
2016/11/29 Coordination with vendor about release of blog post
2016/12/13 Rechecked status with vendor about release date
2016/12/23 Vendor releases fixed version 2.1.3

Summary

The lesson learned by this vulnerability is that one should never trust array keys in PHP. Despite, these should be treated with care as any other variable. The security issue could be detected successfully by RIPS due to its precise array handling and its comprehensive analysis of PHP object injection vulnerabilities. We would like to thank the e107 team for the very professional collaboration. They responded fast and worked hard until the very last minute in order to provide a fixed version. We urge all users to update to the latest version.


Follow us on Twitter to be notified when the next gift of our advent calendar is opened!

APAV Time Table

Date Author Title
24 Dec 2016 Johannes Dahse What we learned from our Advent Calendar
23 Dec 2016 Hendrik Buchwald e107 2.1.2: SQL Injection through Object Injection
22 Dec 2016 Daniel Peeren Security Compliance with Static Code Analysis
21 Dec 2016 Martin Bednorz AbanteCart 1.2.8 - Multiple SQL Injections
20 Dec 2016 Martin Bednorz Kliqqi 3.0.0.5: From Cross-Site Request Forgery to Code Execution
19 Dec 2016 Robin Peraglie osClass 3.6.1: Remote Code Execution via Image File
18 Dec 2016 Daniel Peeren Continuous Integration - Jenkins at your service
17 Dec 2016 Johannes Dahse OpenConf 5.30 - Multi-Step Remote Command Execution
16 Dec 2016 Robin Peraglie Redaxo 5.2.0: Remote Code Execution via CSRF
15 Dec 2016 Dennis Detering Guest Post: Vtiger 6.5.0 - SQL Injection
14 Dec 2016 Hendrik Buchwald The State of Wordpress Security
13 Dec 2016 Johannes Dahse phpBB 2.0.23 - From Variable Tampering to SQL Injection
12 Dec 2016 Martin Bednorz Teampass 2.1.26.8: Unauthenticated SQL Injection
11 Dec 2016 Daniel Peeren Rescanning Applications with RIPS
10 Dec 2016 Hendrik Buchwald Non-Exploitable Security Issues
9 Dec 2016 Hendrik Buchwald Precurio 2.1: Remote Command Execution via Xinha Plugin
8 Dec 2016 Martin Bednorz PHPKit 1.6.6: Code Execution for Privileged Users
7 Dec 2016 Hendrik Buchwald Serendipity 2.0.3: From File Upload to Code Execution
6 Dec 2016 Robin Peraglie Roundcube 1.2.2: Command Execution via Email
5 Dec 2016 Hendrik Buchwald Expression Engine 3.4.2: Code Reuse Attack
4 Dec 2016 Johannes Dahse Introducing the RIPS analysis engine
3 Dec 2016 Martin Bednorz eFront 3.6.15: Steal your professors password
2 Dec 2016 Martin Bednorz Coppermine 1.5.42: Second-Order Command Execution
1 Dec 2016 Hendrik Buchwald FreePBX 13: From Cross-Site Scripting to Remote Command Execution
25 Nov 2016 Martin Bednorz Announcing the Advent of PHP Application Vulnerabilities

Disclaimer: The information provided here is for educational purposes only. It is your responsibility to obey all applicable local, state and federal laws. RIPS Technologies GmbH assumes no liability and is not responsible for any misuse or damages caused by direct or indirect use of the information provided.