Security Bulletin 2018-002

The following vulnerability has been identified:

Synopsis

An attacker would be able to take over access of a user account by entering an e-mail address similar to an already existing e-mail address in the database when using the password reset function.

State

  • until now, no 0-day exploit is known
  • resolved, patch releases as well a workaround available

Impact

By entering a specially crafted e-mail address, an attacker is able to receive a message with the link to change the password to his own inbox and this way might take over access of a user account. This is only possible if an attacker correctly guesses or knows the e-mail address of any shop user and has registered a similar domain name like the one of the user e-mail. Additionally, it is not possible to reproduce in browsers that use punycode.

Affected products, releases and platforms

Products:

  • OXID eShop Enterprise Edition (“EE”)
  • OXID eShop Professional Edition (“PE”)
  • OXID eShop Community Edition (“CE”)

Releases:

  • All OXID eShop versions (EE) up to 5.3.7
  • All OXID eShop versions (PE and CE) up to 4.10.7
  • All OXID eShop 6 versions up to 6.0.2

Platforms:

  • Named above releases are affected on all platforms

Resolution

The issue has already been resolved in the following releases:

  • OXID eShop Enterprise Edition v6.1.0
  • OXID eShop Professional Edition v6.1.0
  • OXID eShop Community Edition v6.1.0
  • OXID eShop Enterprise Edition v6.0.3
  • OXID eShop Professional Edition v6.0.3
  • OXID eShop Community Edition v6.0.3
  • OXID eShop Enterprise Edition v5.3.8
  • OXID eShop Professional Edition v4.10.8
  • OXID eShop Community Edition v4.10.8

Bug tracker entry (will remain in “private” state until the security bulletin is published): https://bugs.oxid-esales.com/view.php?id=6818

Workarounds

For OXID eShop 5.3 (EE) & 4.10 (CE, PE):

  • Please find the method sendForgotPwdEmail() around line 719 in core/oxemail.php
    Replace all the content of the method with this code:
        $result = false;
        $oShop = $this->_addForgotPwdEmail($this->_getShop());
        $sOxId = $this->_getUserIdByUserName($sEmailAddress, $oShop->getId());
        $oUser = oxNew('oxuser');
        if ($sOxId && $oUser->load($sOxId)) {
            // create messages
            $oSmarty = $this->_getSmarty();
            $this->setUser($oUser);
            $this->_processViewArray();
            $this->_setMailParams($oShop);
            $this->setBody($oSmarty->fetch($this->_sForgotPwdTemplate));
            $this->setAltBody($oSmarty->fetch($this->_sForgotPwdTemplatePlain));
            $this->setSubject(($sSubject !== null) ? $sSubject : $oShop->oxshops__oxforgotpwdsubject->getRawValue());
            $sFullName = $oUser->oxuser__oxfname->getRawValue() . " " . $oUser->oxuser__oxlname->getRawValue();
            $sRecipientAddress = $oUser->oxuser__oxusername->getRawValue();
            $this->setRecipient($sRecipientAddress, $sFullName);
            $this->setReplyTo($oShop->oxshops__oxorderemail->value, $oShop->oxshops__oxname->getRawValue());
            if (!$this->send()) {
                $result = -1; // failed to send
            } else {
                $result = true; // success
            }
        }
        return $result;
  • Add a new private method _getUserIdByUserName() at the end of the oxemail.php file
    /**
     * @param string $sUserName
     * @param int    $ShopId
     *
     * @return false|string
     */
    private function _getUserIdByUserName($sUserName, $ShopId)
    {
        $sSelect = "SELECT `OXID` 
          FROM `oxuser` 
          WHERE `OXACTIVE` = 1 
          AND `OXUSERNAME` = ? 
          AND `OXPASSWORD` != ''";
        if ($this->getConfig()->getConfigParam('blMallUsers')) {
            $sSelect .= "ORDER BY OXSHOPID = ? DESC";
        } else {
            $sSelect .= "AND OXSHOPID = ?";
        }
        $sOxId = oxDb::getDb()->getOne(
            $sSelect,
            array(
                $sUserName,
                $ShopId)
        );
        return $sOxId;
    }

For OXID eShop 6.0.x (CE, PE, EE):

  • Go to the Core/Email.php file and move use oxSystemComponentException; below use Exceptionaround line 9
  • Find the method sendForgotPwdEmail() around line 730. Replace all the content of the method with this code:
        $result = false;
        $shop = $this->_addForgotPwdEmail($this->_getShop());
        $oxid = $this->getUserIdByUserName($emailAddress, $shop->getId());
        $user = oxNew(\OxidEsales\Eshop\Application\Model\User::class);
        if ($oxid && $user->load($oxid)) {
            // create messages
            $smarty = $this->_getSmarty();
            $this->setUser($user);
            $this->_processViewArray();
            $this->_setMailParams($shop);
            $this->setBody($smarty->fetch($this->_sForgotPwdTemplate));
            $this->setAltBody($smarty->fetch($this->_sForgotPwdTemplatePlain));
            $this->setSubject(($subject !== null) ? $subject : $shop->oxshops__oxforgotpwdsubject->getRawValue());
            $fullName = $user->oxuser__oxfname->getRawValue() . " " . $user->oxuser__oxlname->getRawValue();
            $recipientAddress = $user->oxuser__oxusername->getRawValue();
            $this->setRecipient($recipientAddress, $fullName);
            $this->setReplyTo($shop->oxshops__oxorderemail->value, $shop->oxshops__oxname->getRawValue());
            if (!$this->send()) {
                $result = -1; // failed to send
            } else {
                $result = true; // success
            }
        }
        return $result;
  • Add a new private method getUserIdByUserName() at the end of the Email.php file
    /**
     * @param string $userName
     * @param int    $shopId
     *
     * @return false|string
     */
    private function getUserIdByUserName($userName, $shopId)
    {
        $select = "SELECT `OXID` 
          FROM `oxuser` 
          WHERE `OXACTIVE` = 1 
          AND `OXUSERNAME` = ? 
          AND `OXPASSWORD` != ''";
        if ($this->getConfig()->getConfigParam('blMallUsers')) {
            $select .= "ORDER BY OXSHOPID = ? DESC";
        } else {
            $select .= "AND OXSHOPID = ?";
        }
        $sOxId = \OxidEsales\Eshop\Core\DatabaseProvider::getDb()->getOne(
            $select,
            [$userName,
             $shopId]
        );
        return $sOxId;
    }

Credits

Many thanks to Hongkun Zeng from Zhejiang University & VULNSPY.com for this report.

Stay up-to-date

To receive upcoming OXID Security Bulletins, please subscribe to the RSS feed: https://oxidforge.org/en/shop/development-security/feed.

How to report security issues

Learn how to report security issues in the Security overview page.



Start the discussion at OXID forums