kaixin大佬tql!
前言
在2020-11-23
号,在twitter
上看到有师傅发了,Zend Framework
框架的一条反序列化链。之后也分析了下,找到了几条链子,之后跟了跟其他版本的,都是存在反序列化漏洞的。然后就出了两个题目,一个 最新版的 laminas 和一个ZendFramework 1 的链子。来写下文章抛砖引玉吧,应该还是有很多的链子的。
1. ZEND 1反序列化链分析
1.1 获取源码&创建zf1项目
其实一开始照这个框架就找了我一阵,因为zend framework
已经到了zf4
(laminas)了,而这个反序列化链子是zf1
,所以我们需要先从https://github.com/zendframework/zf1
中下载到源码,然后使用
然后进入bin
目录使用如下命令,来创建一个项目目录web1
。接着我们把libary
中的Zend
目录移动到项目目录web1/libary
中
zf create project web1
这样我们就得到了一个zf1
框架。接着我们修改一下application\controllers\IndexController.php
<?php
class IndexController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
// action body
unserialize(base64_decode($_POST['Mrkaixin']));
return "Mrkaixin";
}
}
1.2 图说POP链
先抛出整个利用栈吧。
Callback.php:150, Zend_Filter_Callback->filter()
Inflector.php:473, Zend_Filter_Inflector->filter()
Layout.php:780, Zend_Layout->render()
Mail.php:371, Zend_Log_Writer_Mail->shutdown()
Log.php:366, Zend_Log->__destruct()
IndexController.php:14, IndexController->indexAction()
...
Application.php:384, Zend_Application->run()
index.php:26, {main}()
整个pop链切入点在library\Zend\Log.php
中的__destruct
这里遍历了$this->_writers
,并且触发了其中对象的shutdown()
方法。这里我们使用的是Zend_Log_Writer_Mail
这个类的shutdown()
接着跟进这个filter
这里其实可以看到这个链子的亮点就是,两个filter
函数的调用。以及最后的create_function
的命令注入。给人的感觉就是这个链子非常连贯。赞
1.3. 挖掘潜藏的反序列化链
这里其实还有很多的链子,这里丢一条挺简单的链子。
1.3.1 写Shell
先放上调用栈
File.php:464, Zend_CodeGenerator_Php_File->write()
Yaml.php:104, Zend_Config_Writer_Yaml->render()
Mail.php:371, Zend_Log_Writer_Mail->shutdown()
Log.php:366, Zend_Log->__destruct()
IndexController.php:14, IndexController->indexAction()
...
Application.php:384, Zend_Application->run()
index.php:26, {main}()
我们使用public function render\(\)
这个正则来搜索一下,有没有可以利用的render()
函数。
最后锁定了library\Zend\Config\Writer\Yaml.php
public function render()
{
// 这里可以自己跟一下,很简单就可以绕过的。
// $data 可以是任意的。
$data = $this->_config->toArray();
$sectionName = $this->_config->getSectionName();
$extends = $this->_config->getExtends();
if (is_string($sectionName)) {
$data = array($sectionName => $data);
}
foreach ($extends as $section => $parentSection) {
$data[$section][Zend_Config_Yaml::EXTENDS_NAME] = $parentSection;
}
// Ensure that each "extends" section actually exists
foreach ($data as $section => $sectionData) {
if (is_array($sectionData) && isset($sectionData[Zend_Config_Yaml::EXTENDS_NAME])) {
$sectionExtends = $sectionData[Zend_Config_Yaml::EXTENDS_NAME];
if (!isset($data[$sectionExtends])) {
// Remove "extends" declaration if section does not exist