e107 2.1.2: SQL Injection through Object Injection


e107

The 23rd gift in our advent calendar presents security issues in e107, a content management system that is in development since 2013. Among others, we identified a critical issue that allows any user to update his permissions and to extract sensitive information from the database by exploiting a PHP object injection vulnerability.

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.

See RIPS report

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

353354355356357
$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

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

e107_handlers/mysql_class.php

11601161116211631164
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

108310841085108610871088108910901091
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'] : '');

124712481249125012511252
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

DateWhat
2016/11/18First contact with vendor
2016/11/21Send details to vendor
2016/11/27Vendor pushes fix for most critical vulnerabilities to repository
2016/11/29Vendor starts patching the less-severe vulnerabilities
2016/11/29Coordination with vendor about release of blog post
2016/12/13Rechecked status with vendor about release date
2016/12/23Vendor 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

DateAuthorTitle
24 Dec 2016Johannes DahseWhat we learned from our Advent Calendar
23 Dec 2016Hendrik Buchwalde107 2.1.2: SQL Injection through Object Injection
22 Dec 2016Daniel PeerenSecurity Compliance with Static Code Analysis
21 Dec 2016Martin BednorzAbanteCart 1.2.8 - Multiple SQL Injections
20 Dec 2016Martin BednorzKliqqi 3.0.0.5: From Cross-Site Request Forgery to Code Execution
19 Dec 2016Robin PeraglieosClass 3.6.1: Remote Code Execution via Image File
18 Dec 2016Daniel PeerenContinuous Integration - Jenkins at your service
17 Dec 2016Johannes DahseOpenConf 5.30 - Multi-Step Remote Command Execution
16 Dec 2016Robin PeraglieRedaxo 5.2.0: Remote Code Execution via CSRF
15 Dec 2016Dennis DeteringGuest Post: Vtiger 6.5.0 - SQL Injection
14 Dec 2016Hendrik BuchwaldThe State of Wordpress Security
13 Dec 2016Johannes DahsephpBB 2.0.23 - From Variable Tampering to SQL Injection
12 Dec 2016Martin BednorzTeampass 2.1.26.8: Unauthenticated SQL Injection
11 Dec 2016Daniel PeerenRescanning Applications with RIPS
10 Dec 2016Hendrik BuchwaldNon-Exploitable Security Issues
9 Dec 2016Hendrik BuchwaldPrecurio 2.1: Remote Command Execution via Xinha Plugin
8 Dec 2016Martin BednorzPHPKit 1.6.6: Code Execution for Privileged Users
7 Dec 2016Hendrik BuchwaldSerendipity 2.0.3: From File Upload to Code Execution
6 Dec 2016Robin PeraglieRoundcube 1.2.2: Command Execution via Email
5 Dec 2016Hendrik BuchwaldExpression Engine 3.4.2: Code Reuse Attack
4 Dec 2016Johannes DahseIntroducing the RIPS analysis engine
3 Dec 2016Martin BednorzeFront 3.6.15: Steal your professors password
2 Dec 2016Martin BednorzCoppermine 1.5.42: Second-Order Command Execution
1 Dec 2016Hendrik BuchwaldFreePBX 13: From Cross-Site Scripting to Remote Command Execution
25 Nov 2016Martin BednorzAnnouncing 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.

Tags: hendrik buchwald, php, security, e107, apav, sql injection, php object injection,

Author: Hendrik Buchwald

CISO, Co-Founder

Hendrik graduated in computer science at the Ruhr-University Bochum and is a professional software engineer. In addition to designing and building complex systems, he particularly enjoys breaking and securing web applications. He is an experienced security consultant and the lead developer of the open source web application firewall Shadow Daemon.

Comments

comments powered by Disqus