问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
ThinkPHP 5.x 系列文件上传getshell
漏洞分析
开发者使用 官方文件上传示例进行开发时,存在一个文件上传漏洞导致 getshell
本文仅用于技术讨论与研究,文中的实现方法切勿应用在任何违法场景。如因涉嫌违法造成的一切不良影响,本文作者概不负责。 0x00 漏洞简介 --------- 2022年12月出的一个 `CVE` ,漏洞作者在10月左右就写在`thinkphp` 的 `github` 下面了,链接在这:<https://github.com/top-think/framework/issues/2772> ,此漏洞属于框架函数的漏洞,需要开发者编写代码时使用到该函数才有机会利用。 在官方开发手册的示例中,使用了该函数,并且没有任何过滤,因此当开发者使用 [官方示例](https://www.kancloud.cn/manual/thinkphp5_1/354121) 进行开发时,就可以 `getshell`。 0x01 漏洞影响 --------- `thinkphp 5.x` 系列 不影响目前的 `thinkphp6.x` 0x02 环境搭建 --------- 使用 `composer` 快速搭建 `thinkphp5.x` 系列最新版环境 ```php composer create-project topthink/think=5.1.* tp5.1.41 ``` 之后根据官方示例 [https://www.kancloud.cn/manual/thinkphp5\_1/354121](https://www.kancloud.cn/manual/thinkphp5_1/354121) 编写,修改如下文件 ```php application/index/controller/Index.php ``` ```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` ,跟进该方法 ```php 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` 开始一直到最新版本,都是这样的,没有更改过。
发表于 2022-12-19 09:00:01
阅读 ( 7986 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
shenwu
10 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!