RIPS Analysis

RIPS’ analysis of the ~77,000 lines of Kliqqi code took only 31 seconds to complete and was able to discover several risks within the application. There were no critical vulnerabilities found directly but it is possible to escalate one high-rated security issue to a critical one - as we are going to demonstrate in the following case study.

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

In this case study we are going to present a chain of vulnerabilities that ultimately lead to code execution on the attacked server by

  1. installing the upload module,
  2. allowing .php extensions in the upload module,
  3. and uploading a malicious PHP file.

Install / Activate Upload Module

The installation of a module by an Kliqqi administrator requires only a few HTTP GET requests. Hence, a very simple malicious link can be crafted that is able to install arbitrary modules in the application. It is sufficient to lure an administrator into clicking this link to install the upload module that is required for the vulnerability chain explained in this post. Exploitation of this security issue is possible due to the fact that there is no sufficient protection against cross-site request forgery attacks. The referrer check shown in the code summary below can be easily bypassed.

libs/html1.php

1105
1106
1107
1108
1109
1110
1111
function check_referrer($post_url=false) {
    
    if (strpos(preg_replace('/^.+:\/\/(www.)?/','',$_SERVER['HTTP_REFERER']).'/',
    preg_replace('/^.+:\/\/(www.)?/','',$my_base_url))!==0) {
        unset($_SESSION['xsfr']);
        die("Wrong Referrer '{$_SERVER['HTTP_REFERER']}'");
    }

The regular expressions in both calls to preg_replace() only remove the protocol and www subdomain used for the request and base url in the variable $my_base_url. By default, when Kliqqi is installed at the domain www.example.com, the $my_base_url variable is set to http://www.example.com. Now, the if statement checks whether the base url is positioned at the beginning of the HTTP referrer. This check can be easily circumvented by simply prepending the domain of the targeted application to the attacker controlled domain as a subdomain. In our example, an attacker can circumvent the referrer check by using the following domain: http://example.com.attacker.com. First, the $my_base_url variable and the referrer are striped to example.com and example.com.attacker.com respectively. Obviously, the check whether example.com is at the beginning of example.com.attacker.com via the strpos() function succeeds.

In general, relying on the HTTP referrer should be avoided because it can be easily manipulated by malicious users and oftentimes it is not available at all (company proxy etc.). It is recommended to use CSRF tokens for proper security.

Allow PHP Extension for Uploads

This step is even simpler than the previous one, as the referrer check is not executed in this particular module. With JavaScript and CSRF it is possible to perform a simple POST request to module.php?module=upload on a client with administration privileges to add new extensions that are allowed within the upload module. As a result, it is possible to upload arbitrary PHP files to the targeted web server by any user in the social community. Similar to the previous step, CSRF tokens should be used in order to prevent this type of attack. In addition, it should not be allowed to change the file extension whitelist arbitrarily in order to prevent the upload of malicious PHP files.

Upload PHP Files

Once the attacker added php to the allowed extension list as described in the previous steps, it is possible to upload arbitrary PHP code by using the following file upload functionality.

modules/upload/upload_main.php

186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
function upload_save_files() {
    $settings = get_upload_settings();
    $extensions = preg_split('/[ ,.]+/',$settings['extensions']);
    
    $tmp_name = $_FILES["upload_files"]["tmp_name"][$key];
    $name = $_FILES["upload_files"]["name"][$key];
    if ($ext = strrchr($name,'.')) {
        $name = str_replace($ext,'',$name);
        $ext  = substr($ext,1);
    }
    if ($ext && in_array(strtolower($ext),$extensions)) {
        if (@move_uploaded_file($tmp_name, "$upload_dir/$name.$ext")) {

function get_upload_settings() {
    $sql = "SELECT * FROM ".table_prefix."misc_data WHERE `name` like 'upload%'";
    $settings = $db->get_results($sql);
    

Here, the allowed file extensions in the validation check in line 197 are read from the database in line 201, making it possible to upload PHP files. Once again, as demonstrated in several previous blog posts, a file upload causes the trouble.

Putting it all together

All of the attack steps described in the case study above can be packaged into a single JavaScript payload because of the missing CSRF protection. In addition, there is no cross-site scripting issue required on the attacked application itself and all of the payload can be executed via a malicious website prepared by an attacker. The only prerequisite is that he has to lure a privileged user onto his website so that the payload can be executed invisible in the background, which in most cases requires only a handful of social engineering.

Time Line

Date What
2016/10/24 First try to contact vendor
2016/11/16 Second try to contact vendor
2016/11/16 Vendor responded
2016/12/17 Vendor released a fixed version

Summary

Cross-site request forgery protection is critical to remedy vulnerability chains such as the one presented in this blog post. In addition, allowing the upload of (basically) user-defined file extensions is never a good idea. Instead, the file extension whitelist should be more strict and under no circumstances allow PHP files to be uploaded in order to prevent malicious code execution. We thank the vendor for the professional handling of these issues and for providing security patches.


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.