ThinkPHP 5.x 系列文件上传getshell

admin 2022年12月28日12:22:39评论138 views字数 2660阅读8分52秒阅读模式
目录0x00 漏洞简介0x01 漏洞影响0x02 环境搭建0x03 漏洞分析0x04 漏洞复现0x05 总结

开发者使用 官方文件上传示例进行开发时,存在一个文件上传漏洞导致 getshell

本文仅用于技术讨论与研究,文中的实现方法切勿应用在任何违法场景。如因涉嫌违法造成的一切不良影响,本文作者概不负责。

0x00 漏洞简介

2022年12月出的一个 CVE ,漏洞作者在10月左右就写在thinkphp 的 github 下面了,链接在这:https://github.com/top-think/framework/issues/2772 ,此漏洞属于框架函数的漏洞,需要开发者编写代码时使用到该函数才有机会利用。

在官方开发手册的示例中,使用了该函数,并且没有任何过滤,因此当开发者使用 官方示例 进行开发时,就可以 getshell

0x01 漏洞影响

thinkphp 5.x 系列

不影响目前的 thinkphp6.x

0x02 环境搭建

使用 composer 快速搭建 thinkphp5.x 系列最新版环境

composer create-project topthink/think=5.1.* tp5.1.41

之后根据官方示例 https://www.kancloud.cn/manual/thinkphp5_1/354121 编写,修改如下文件

application/index/controller/Index.php
<?php
namespace appindexcontroller;

class Index
{
public function Index(){
// 获取表单上传文件 例如上传了001.jpg
$file = request()->file('image');
// 移动到框架应用根目录/uploads/ 目录下
$info = $file->move( '../uploads');
if($info){
// 成功上传后 获取上传信息
// 输出 jpg
echo $info->getExtension();
// 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg
echo $info->getSaveName();
// 输出 42a79759f284b767dfcb2a0197904287.jpg
echo $info->getFilename();
}else{
// 上传失败获取错误信息
echo $file->getError();
}
}
}

0x03 漏洞分析

官方示例文件中注释写的很明白,就是先上传文件,然后将文件移动到根目录的 uploads 文件夹下,后面代码就是在输出。

我们先看第一句 request()->file('image');

request() 直接加载了 thinkphp/library/think/Request.php 中的 Request 类,然后访问 file 方法

ThinkPHP 5.x 系列文件上传getshell

这里就是取到了 $_FILES 与 $name ,然后传入 dealUploadFile 方法,返回一个 $array ,最后会返回一个 $array[$name] ,我们跟进 dealUploadFile 方法

ThinkPHP 5.x 系列文件上传getshell

我们传进来的 $files 是 $_FILES ,因此不满足第一个 if 条件,$file['name'] 就是传入的 filename ,不为数组时就会进入最后的 else ,正常传入文件就不会出现 error ,因此来到 1246 行,这时候进入 thinkphp/library/think/File.php 的 setUploadInfo 方法,来到这里

ThinkPHP 5.x 系列文件上传getshell

这里返回了 $this ,也就是实例化后的 File 类。

然后继续返回,可以看到,我们编写的文件中,第一句最后的返回就是这个实例化后的 File 类

看到第二句 $file->move( '../uploads') ,调用该类的 move 方法,参数是 ../uploads ,跟进该方法

thinkphp/library/think/File.php

ThinkPHP 5.x 系列文件上传getshell

这里是 move 方法的上半部分,代码都有注释,因此很好理解,涉及到检测的有三个方法,分别是 isValid 、check 、chechPath ,我们依次看看

isValid 方法

ThinkPHP 5.x 系列文件上传getshell

这里只是检测是不是文件或者上传的文件,显然是满足的。

check 方法

ThinkPHP 5.x 系列文件上传getshell

此处的参数是没有传入的,因此 $rule 就是空数组

第一句这里,由于 $rule 为空,因此会获得 $this->validate 的值,这个 $this->validate 的值是在 validate 方法中设置的,如下

ThinkPHP 5.x 系列文件上传getshell

按照官方示例的代码,是没有写这个 validate 限制的,这里 validate 默认也是空数组,因此 $rule 的值也还是空的,其实如果要防止这个漏洞的话,也是可以利用这个 validate 方法进行设置的。

由于 $rule 为空数组,因此前面三个判断都不会生效,只会进行第四个,也就是 $this->checkImg() 方法,只要这个方法返回 true ,那么就会跳过这里的判断,我们来看到这个方法

ThinkPHP 5.x 系列文件上传getshell

这个方法检查图片后缀以及图片类型。

首先获取后缀并转为小写,得到 $extension ,下面是一个判断,图片后缀为这个数组里面的值并且后面也为 true 时就会返回错误,这里的条件很奇葩,当我们的文件后缀为 php 时就不满足第一个条件,直接返回 true

chechPath 方法

ThinkPHP 5.x 系列文件上传getshell

这里只是判断有没有相应文件夹,没有就创建,因此也可以过

接下来看看 move 方法的下半部分

ThinkPHP 5.x 系列文件上传getshell

这里并没有其他的检测了,直接将临时文件移动到了目标文件。

我们直接上传一个 php 文件,即可在使用官方示例的条件下 getshell

0x04 漏洞复现

由于官方示例没有上传的模板,因此我们自己创建一个

ThinkPHP 5.x 系列文件上传getshell

上传并且抓包,将后面改为 php,如图

ThinkPHP 5.x 系列文件上传getshell

ThinkPHP 5.x 系列文件上传getshell

0x05 总结

这个漏洞是属于thinkphp框架的函数的漏洞,因此需要开发者按照官方示例去使用或者类似的用法才会造成 getshell 。

但是也会觉得很奇葩,因为此处的实际检测应该就是那处 checkImg 方法,但他这里明显就写错,必须属于图片类型才会返回 false ,根本上就没有对危险的后缀进行过滤,更让人觉得离谱的是,至少从 5.0.0 开始一直到最新版本,都是这样的,没有更改过。

https://forum.butian.net/share/2058


原文始发于微信公众号(白帽子程序员):ThinkPHP 5.x 系列文件上传getshell

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年12月28日12:22:39
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ThinkPHP 5.x 系列文件上传getshellhttp://cn-sec.com/archives/1483636.html

发表评论

匿名网友 填写信息