RIPS detected a highly critical vulnerability in the OXID eShop software that allows unauthenticated attackers to takeover an eShop remotely in less than a few seconds - all on default configurations. A second vulnerability in the administration panel can then be exploited to gain remote code execution on the server. We highly recommend to update to the latest version!

OXID eShop is an e-commerce shop software originating from Germany and its enterprise edition is used by industry leaders such as Mercedes, BitBurger and Edeka. In this technical blog post we will show you how an unauthenticated attacker gains Remote Code Execution in OXID eShop running the latest version 6.3.4 on default configurations.

The vulnerability was detected with RIPS code analysis in 170.000 lines of code within 3 minutes.

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.

SQL Injection in Product Details

The eShop software is prone to a SQL Injection which is fully exploitable from an unauthenticated remote session. The exploit requires no specific shop configuration.

Each time when a user is viewing a product a specific SQL query is constructed by the _getVendorSelect() method and sent to the database.

source/Application/Model/ArticleList.php

1083 1084 1085 1086 1087 1088 1089 1090 protected function _getVendorSelect ( $sVendorId ) { ⋮ if ( $this -> _sCustomSorting ) { $sSelect .= " ORDER BY { $this -> _sCustomSorting } " ; } return $sSelect ; }

A preceding call to the setCustomSorting() method will specify the _sCustomSorting property of the object on line 1087, which determines the ORDER BY clause of the SQL query. Later, this will be the injection point of the attacker.

source/Application/Component/Locator.php

131 132 $oIdList -> setCustomSorting ( $oLocatorTarget -> getSortingSql ( $oLocatorTarget -> getSortIdent ()));

The custom sorting property is set to the return value of the method getSortingSql() on line 131 of the above code snippet. This call is delegated via the getSorting() method to the getSavedSorting() method of the FrontendController class on line 1424:

source/Application/Controller/FrontendController.php

1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 public function getSorting ( $sortIdent ) { ⋮ if ( $sorting = $this -> getUserSelectedSorting ()) { /*...*/ } elseif ( ! $sorting = $this -> getSavedSorting ( $sortIdent )) { $sorting = $this -> getDefaultSorting (); } /*...*/ public function getSavedSorting ( $sortIdent ) { $sorting = \OxidEsales\Eshop\Core\Registry :: getSession () -> getVariable ( 'aSorting' ); /*...*/ return $sorting [ $sortIdent ]; }

It can be observed that the getSavedSorting() method accesses OXID’s internal session object on line 1430 and retrieves the aSorting variable - this line is equivalent of reading PHP’s session variable $_SESSION['aSorting'] directly. This variable can be controlled by an attacker, which is a keypoint in understanding the vulnerability. Finally, the variable is written to the $sorting placeholder on line 1430, returned through the call stack and used as an argument to the previously described setCustomSorting() method.

source/Application/Component/Widget/ArticleDetails.php

899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 protected function _setSortingParameters () { $sSortingParameters = $this -> getViewParameter ( 'sorting' ); /*...*/ list ( $sSortBy , $sSortDir ) = explode ( '|' , $sSortingParameters ); $this -> setItemSorting ( $this -> getSortIdent (), $sSortBy , $sSortDir ); } /*...*/ public function setItemSorting ( $sortIdent , $sortBy , $sortDir = null ) { /*...*/ $sorting [ $sortIdent ][ 'sortby' ] = $sortBy ; $sorting [ $sortIdent ][ 'sortdir' ] = $sortDir ? $sortDir : null ; \OxidEsales\Eshop\Core\Registry :: getSession () -> setVariable ( 'aSorting' , $sorting );

In the following paragraph we will see how an attacker can control this variable: Just before the SQL query is constructed and sent to the database the attacker overrides the $_SESSION['aSorting'] variable with user input. This is done by a preceding invocation of the method _setSortingParameters() which retrieves the user-controlled sorting parameter on line 901 of the source code listing. The method then calls the setItemSorting() function on line 904 to store the potentially malicious user input into the $_SESSION['aSorting'] variable, by making use of the getSession()->setVariable() construct on line 912.

SQL injected query

899 SELECT ... ORDER BY oxtitle ; INSERT INTO oxuser (...) VALUES (...);

This means an attacker can pivot via the session variable to inject straight into ORDER BY statement of the SQL query. Since the underlying database driver is per default set to PDO, an attacker can make use of stacked queries to insert a brand new admin user with a password of his choice. He can then log into the backend and continue the exploitation process which is described in the following section.

Exploiting an Admin RCE

As soon as the adversary has access to the backend, he can escalate his access into a Remote Code Execution by exploiting a PHP Object Injection vulnerability in the import section. The administrator has the possibility to import articles by uploading a CSV file which is loaded into the $data array of the following code snippet.

source/Core/GenericImport/ImportObject/OrderArticle.php

28 29 30 protected function preAssignObject ( $shopObject , $data , $allowCustomShopId ){ /*...*/ $persParamValues = @ unserialize ( $data [ 'OXPERSPARAM' ]);

On line 30, values of the column OXPERSPARAM are thrown unsanitized into the unserialize() function leading a PHP Object Injection. To learn more about PHP Object Injections and how to turn them into a Remote Code Execution you can check out our PHP Object Injection blogpost. The following video demonstrates a fully automated exploit PoC that uses the vulnerabilities described in this post.

Timetable

Date Event 11/Dec/2017 Reported a SQL Injection in OXID 4.10.6 18/June/2019 First contact with vendor 19/June/2019 Agreed on communication encryption 21/June/2019 Sent vulnerability details 27/June/2019 Vendor informs about releasing fix on 30th July 30/July/2019 Vendor fixed issue

Summary

The herein described vulnerabilities affecting OXID eShop illustrate how the combination of two critical vulnerabilities can lead to an exploit that hands the total control of a shop to a remote attacker. It stresses the importance of continuously integrated security testing to minimize risk factors in sensitive source code. We would like to thank the OXID security team for the professional and timely response and we highly recommend to update all OXID eShops to the latest version.