Blog post

Pre-Auth Takeover of OXID eShops

Robin Peraglie photo

Robin Peraglie

Vulnerability Researcher

8 min read

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. 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!

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

A preceding call to the setCustomSorting() method will specify the _sCustomSortingproperty 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      $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    public function getSorting($sortIdent)
1420    {
1421        ⋮
1422        if ($sorting = $this->getUserSelectedSorting()) {
1423            /*...*/
1424        } elseif (!$sorting = $this->getSavedSorting($sortIdent)) {
1425            $sorting = $this->getDefaultSorting();
1426        }
1427        /*...*/
1428        public function getSavedSorting($sortIdent)
1429        {
1430            $sorting = \OxidEsales\Eshop\Core\Registry::getSession()
1431                ->getVariable('aSorting');
1432            /*...*/
1433            return $sorting[$sortIdent];
1434        }

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

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    protected function preAssignObject($shopObject, $data, $allowCustomShopId){
29       /*...*/
30       $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

DateWhat
11/Dec/2017Reported a SQL Injection in OXID 4.10.6
18/June/2019First contact with vendor
19/June/2019Agreed on communication encryption
21/June/2019Sent vulnerability details
27/June/2019Vendor informs about releasing fix on 30th July
30/July/2019Vendor 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.