zend framework3反序列化漏洞复现分析

zend framework3 反序列化漏洞复现分析

环境安装

composer下载

composer create-project zendframework/skeleton-application

然后进入目录 php -S 0.0.0.0:8099 -t public 启动
图片

修改module/Application/src/Controller/IndexController.php
图片
生成poc,poc.php
图片
发送请求,环境搭建成功
图片

漏洞复现分析:

查看POC


根据POC进行分析

  1. Zend\Http\Response\Stream
    图片
    __destruct方法中的unlink ,unlink函数的第一个参数为String类型,如果$this->streamName为一个类,即可触发__toString方法

  2. 根据PoC对Zend\View\Helper\Gravatar进行分析
    图片

__toString调用了getImgTag方法,跟进getImgTag
图片

跟进setSrcAttribForImg,就是设置attributes的值,这个值是可控的,attributes需要为一个数组
图片
跟进htmlAttribs,该方法有一个attributes,为 getImgTag传入

图片

继续跟进$this->getView(), AbstractHelper->getView

图片
AbstractHelper类只有get set,先跟进plugin,PhpRenderer-> plugin,所以$this->getView()需要为PhpRenderer类
图片
跟进PhpRenderer有plugin方法

$__helpers

跟进getHelperPluginManager,
图片
图片
$__helpers也是可以控制的,也$this->getHelperPluginManager()可以控制
图片
4.分析POC $__helpers需要Zend\Config\ReaderPluginManager。跟进ReaderPluginManager,该类中没有get方法,但是该类继承AbstractPluginManager,跟进AbstractPluginManager,get方法

图片
Has方法的$name为escapehtml

$options不可控只能为空,所以$instance从parent:get取值,跟进parent:get,ServiceManager->get

该方法返回$this->

 

services数组,继续跟进validate,
图片

发现services和instanceOf都可控,但是由于

$escaper = $this->getView()->plugin('escapehtml');
$escapeHtmlAttr = $this->getView()->plugin('escapehtmlattr');

所以在序列化ReaderPluginManager时候需要services的key为escapehtml和escapehtmlattr,$this->instanceOf需要为Zend\Validator\Callback(),最终

$escaper为$instanceOf,也就是Zend\Validator\Callback(),所以当运行到$escaper($key)时候会调用__invoke
图片

然后调用Callback 的isValid。跟进isValid
图片
图片
139行有个call_user_func_array $args为1,

$callback = $this->getCallback(),跟进getCallback
图片
图片
$options也可以控制,在序列化时候Callback指定options的值,最后导致远程命令执行

所以整体利用链如下:
图片

  1. Zend\Http\Response\Stream->__destruct()中的unlink()触发Zend\View\Helper\Gravatar->__toString()方法

  2. Zend\View\Helper\Gravatar->__toString()调用Zend\View\Helper\Gravatar->getImgTag()方法,最后触发了

AbstractHtmlElement.php:73的htmlAttribs方法

htmlAttribs中的$this->getView()->plugin为PhpRenderer的plugin,$this->getView(),PhpRenderer->plugin调用了getHelperPluginManager,etHelperPluginManager的__helpers可控

控制__helpers需要为Zend\Config\ReaderPluginManager,Zend\Config\ReaderPluginManager,没有get方法ReaderPluginManager继承AbstractPluginManager,

所以调用了AbstractPluginManager->get,后续调用了ServiceManager->get,AbstractPluginManager继承,ServiceManager,services和instanceOf可控,

所以只需要序列化ReaderPluginManager时指定services和instanceOf,$escaper等于AbstractPluginManager->get返回的instanceOf,也就是Zend\Validator\Callback(),当$escaper($key)的时候会触发Zend\Validator\Callback->__invoke(),终执行Zend\Validator\Callback- isValid()中的call_user_func_array

写的不好勿喷。。

参考连接:

1 个赞