thinkphp框架漏洞分析

thinkphp3.2.3

thinkphp信息泄露

在我们测试的时候,我们随便输入一些垃圾字符,如果得到如下界面,说明thinkphp开启的了debug模式

1657677100313

如果关闭了debug是这样的,虽然关闭了调试模式但是还是可以看到其版本信息,不过有些开发人员会将报错页面修改掉。

1657677158337

一般我们做代码的调试分析,我们会把调试追踪打开

1657677574974

日志信息泄露

http://thinkphp323test.com/Application/Runtime/Logs/Home/22_07_13.log

ThinkPHP在开启DEBUG的情况下会在Runtime(缓存文件)目录下生成日志,如果debug模式不关,可直接输入路径造成目录遍历。
ThinkPHP3.2结构:ApplicationRuntimeLogsHome22_07_13.log
ThinkPHP3.1结构:RuntimeLogsHome22_07_13.log
可以看到是 :项目名RuntimeLogsHome年份_月份_日期.log
这样的话日志很容易被猜解到,而且日志里面有执行SQL语句的记录。

1657678847569

缓存信息泄露

这里我们首先介绍一个危险函数F函数,我们这首先测试F函数

1657679031933

在我们访问过index页面之后,我们可以在Runtime中看到如下文件

1657679134615

同样的,我们可以在页面中访问缓存中生成的文件,所以如果F函数是可控函数就会很危险。

1657679197778

接下来我们介绍S函数,我们使用如下代码进行测试

1657679861951

我们可以在Temp中看到生成如下文件,文件名是data的MD5值

1657679653444

这个文件名可以加key,在配置文件中加入如下代码

1657679814809

我们再次访问index然后查看到如下文件,文件名是"thinkdata"的md5

1657679781251

thinkphp网站框架指纹识别

如果使用的是tp3,我们可以使用如下代码进行判断

/?c=4e5e5d7364f443e28fbf0d3ae744a59a 
#如果网站的Thinkphp目录没有修改,我们还可以通过这个方式进行识别
/ThinkPHP/logo.png

1657680108707

thinkphp数据库操作及其漏洞

thinkphp数据库操作,如果我们使用不当就会造成漏洞的产生,这里我们首先就分析一下数据库的操作是如何执行的,首先我们使用如下测试代码进行调试分析

1657693250810

接着我们进入我们下断的位置,这里我们可以看到进入到了M函数

function M($name='', $tablePrefix='',$connection='') {
    static $_model  = array();
    //strpos返回指定符号在字符串中的位置
    if(strpos($name,':')) {
        list($class,$name)    =  explode(':',$name);//explode 函数把字符串分割为数组
    }else{
        $class      =   'Think\\Model';
    }
    $guid           =   (is_array($connection)?implode('',$connection):$connection).$tablePrefix . $name . '_' . $class;
    //implode() 函数,用于返回一个由数组元素组合成的字符串
    if (!isset($_model[$guid]))
        $_model[$guid] = new $class($name,$tablePrefix,$connection);
    return $_model[$guid];
}

接着我们继续F7进入,这里我们可以看到进入到了where函数,主要作用就是对数据库操作的WHERE进行赋值

public function where($where,$parse=null){
        if(!is_null($parse) && is_string($where)) {
            if(!is_array($parse)) {
                $parse = func_get_args();
                //func_get_args()
                //返回一个数组,其中每个元素都是目前用户自定义函数的参数列表的相应元素的副本。
                array_shift($parse);
                //将数组的第一个移出并作为结果返回,其他的所有单元向前移动一位数组长度减一
            }
            $parse = array_map(array($this->db,'escapeString'),$parse);
            //array_map为数组的每个元素应用回调函数
            $where =   vsprintf($where,$parse);//vsprintf返回格式化字符串
        }elseif(is_object($where)){//检测变量是否是一个对象
            $where  =   get_object_vars($where);
            //get_object_vars返回由对象属性组成的关联数组
        }
        if(is_string($where) && '' != $where){
            $map    =   array();
            $map['_string']   =   $where;
            $where  =   $map;
        }        
        if(isset($this->options['where'])){
            $this->options['where'] =   array_merge($this->options['where'],$where);
            //array_merge()合并一个或多个数组
        }else{
            $this->options['where'] =   $where;
        }
        
        return $this;
    }

最后我们继续F7进入,接着我们进入到了find函数,这里一个关键的语句是执行了select

1657696368793

到这里之后我们继续进入分析,我们可以看到时select函数

public function select($options=array()) {
        $this->model  =   $options['model'];
        $this->parseBind(!empty($options['bind'])?$options['bind']:array());
        $sql    = $this->buildSelectSql($options);
        $result   = $this->query($sql,!empty($options['fetch_sql']) ? true : false);//进行sql查询
        return $result;
    }

最后我么继续F7,进入了buildSelectSql,在这个函数了判断了options['page']是否设置,这里我们没有设置直接跳过了判断,我们继续F7进入,这个地方就是拼凑sql语句的关键部分

 public function parseSql($sql,$options=array()){
        $sql   = str_replace(
            array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%LOCK%','%COMMENT%','%FORCE%'),
            array(
                $this->parseTable($options['table']),
                $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
                $this->parseField(!empty($options['field'])?$options['field']:'*'),
                $this->parseJoin(!empty($options['join'])?$options['join']:''),
                $this->parseWhere(!empty($options['where'])?$options['where']:''),
                $this->parseGroup(!empty($options['group'])?$options['group']:''),
                $this->parseHaving(!empty($options['having'])?$options['having']:''),
                $this->parseOrder(!empty($options['order'])?$options['order']:''),
                $this->parseLimit(!empty($options['limit'])?$options['limit']:''),
                $this->parseUnion(!empty($options['union'])?$options['union']:''),
                $this->parseLock(isset($options['lock'])?$options['lock']:false),
                $this->parseComment(!empty($options['comment'])?$options['comment']:''),
                $this->parseForce(!empty($options['force'])?$options['force']:'')
            ),$sql);
        return $sql;
    }

ctrl+shift+f查找文件中内容

----------------------------未完待续----------------------------

thinkphp3.2简单逻辑漏洞

这个逻辑漏洞是由于thinkphp的自动完成功能所造成的

自动完成是ThinkPHP提供用来完成数据自动处理和过滤的方法,使用create方法创建数据对象的时候会自动完成数据处理。

thinkphp5

thinkphp5配置

当我们没有关闭调试的情况下访问错误地址就会报如下错误

1657726584488

而且可以在底部看到其版本信息

1657726605714

我们可以在配置文件中关闭调试功能

1657726681406

最后修改:2022 年 11 月 11 日
如果觉得我的文章对你有用,请随意赞赏