YII 2 反序列化挖掘与分析
字数 1565 2025-08-30 06:50:35
YII 2 反序列化漏洞挖掘与分析
环境部署
- 选择 YII 2 的 basic 包
- 修改
config/web.php文件,将cookieValidationKey的值改为demo - 访问
/web/index.php - 在
controllers\SiteController.php中的actionIndex方法添加反序列化入口
反序列化漏洞一(版本限制:<=2.0.39)
漏洞分析
-
反序列化起点:
SebastianBergmann\RecursionContext\Context类的__destruct()方法- 该方法包含循环调用逻辑
arrays属性可控,如果赋值为继承了IteratorAggregate类的类,遍历时会调用该类的getIterator()方法
-
关键调用链:
PHPUnit\Framework\TestSuite类的getIterator()方法- 如果
$iteratorFilter属性赋值为类,可以调用任意类的__call()魔术方法 $iteratorFilter属性可控
- 如果
Faker\Generator类的__call()方法- 调用
format()方法 - 存在回调函数调用,
$arguments不可控但getFormatter()返回值可控
- 调用
PHPUnit\Framework\MockObject\MockClass#generate()方法- 直接调用
eval方法 $classCode可控
- 直接调用
EXP 编写
利用上述调用链构造恶意序列化数据,最终通过 eval 执行任意代码。
漏洞修复
在 2.0.39 后的版本中:
Faker\Generator()类添加了__wakeup()方法- 将
$formatters属性置空,使getFormatter()返回值不可控
绕过尝试
理论上可以通过引用绕过 __wakeup() 的置空:
- 将
$formatters与另一个类的属性绑定 - 在
Generator()::__wakeup()后对该属性赋值 - 由于反序列化顺序(先属性后方法),可以绕过限制
实际测试中:
- 发现
Swift_Encoder_QpEncoder类的__wakeup方法对$safeMap赋值 - 通过绑定
$safeMap和$formatters,赋值后$formatters也有值 - 但实际应用中难以找到可直接赋值的
__wakeup或__destruct方法
反序列化漏洞二(版本限制:<=2.0.45)
漏洞分析
- 调用链变化:
- 使用
vendor/fakerphp/faker/src/Faker/ValidGenerator.php的__call()方法- 包含两个回调函数
- 利用点在第二个回调,需要控制
$this->validator和$res
- 利用
vendor/fakerphp/faker/src/Faker/DefaultGenerator.php中的__call()方法返回自定义值
- 使用
EXP 编写
基于新的调用链构造恶意序列化数据,实现代码执行。
总结
- YII 2 反序列化漏洞存在于多个版本中
- 漏洞利用依赖于框架依赖组件的魔术方法调用链
- 修复方案主要通过添加
__wakeup()方法清空关键属性 - 理论上存在绕过方法,但实际利用条件较为苛刻
防御建议
- 及时升级到最新版本
- 避免使用不受信任的序列化数据
- 审查项目中使用的第三方依赖组件
- 实施输入验证和过滤机制