ThinkPHP 5.x 系列文件上传getshell
2022-12-27 23:56:41 Author: 白帽子程序员(查看原文) 阅读量:37 收藏

目录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 app\index\controller;

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 方法

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

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

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

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

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

thinkphp/library/think/File.php

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

isValid 方法

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

check 方法

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

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

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

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

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

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

chechPath 方法

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

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

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

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

0x04 漏洞复现

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

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

0x05 总结

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

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

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

文章来源: http://mp.weixin.qq.com/s?__biz=Mzg3Mjc0MDQ2Nw==&mid=2247490495&idx=1&sn=fabda4ff05e02b23c971dc68ebbef8b9&chksm=ceebf8a3f99c71b5f69f35c05fb4c565efff8c7bdfcc39b1f52c6f5fe709c40f6f0fcd1a9ee2#rd
如有侵权请联系:admin#unsafe.sh