PHP序列化长度变化导致字符逃逸

/ 0评 / 0

[0CTF 2016]piapiapia

 
复现地址:buuoj.cn
打开后是一个登录框

万能密码尝试无果后,url尝试了一下www.zip

发现源码

源码中包含register页面,注册admin居然成功了,之后跳转到了updata页面,这个地方有可利用的点,继续审源码

看了半天,可能是个php反序列化的题目

可以发现在profile中有一个读取文件的函数 并且有unserialize函数


我们可以不可以利用呢?
如果profile文件是config.php而不是photo即可获得flag
此处有一个知识点:PHP序列化长度变化导致字符逃逸
在本地尝试构造序列化文字:

可以发现序列化后的文字为:a:4:{s:5:"phone";s:6:"123456";s:5:"email";s:14:"text128@qq.com";s:8:"nickname";a:1:{i:0;s:4:"hack";}s:5:"photo";s:7:"ha1c9on";}
我们需要把photo中的文字改为:config.php
而我们需要逃逸的字符为:";}s:5:"photo";s:7:"config.php";}
因为config.php为十个字符 所以s:7改为s:10 即:";}s:5:"photo";s:10:"config.php";}
统计字符后发现 需要逃逸的字符有34
在源码中发现

均会被替换成hacker
所以我们使用34where逃逸
payload:where*34";}s:5:"photo";s:10:"config.php";}
为什么select不可以只能用where
因为:这里使用替换的话 使用的字符需要小于替换成的字符才会逃逸出来

这里只有where<hacker

查看proflie.php base64解码就有flag


 
知识点:php序列化长度变化导致字符逃逸
首先, PHP反序列化中值的字符读取多少其实是由表示长度的数字控制的,而且只要整个字符串的前一部分能够成功反序列化,这个字符串后面剩下的一部分将会被丢弃
参考一下大佬博客里面对此的解释

在反序列化输出之前,我们的字符串是在某过滤函数的过滤替换之后得到的,在经过过滤处理了之后,字符串的某一部分会加长,但是描述其长度的数字没有发生改变(由反序列化时变量的属性决定),这就可能导致PHP在按描述其长度的数字读取相应长度的字符串之后,本该属于该字符串的内容逃逸出了该字符串的管辖范围。轻则反序列化失败,重则自成一家成为一个独立于源字符串的变量,若是这个独立出来的变量末尾是个结束符";},则可能导致反序列化成功结束,而后面的内容也顺理成章的被丢弃了,此处能够逃逸出的字符串长度由过滤后字符串增加的长度决定,如上图第四个语句,@号内就是我们要逃逸出来的字符串,长度为33,百分号内为我们输入的username变量,要想让@号内的字符串逃逸,我们就需要原来的字符串增加33,这样的话@号内的字符串就会被挤出它原来所在的位置,username的正常部分和增长的部分正好被php解析成一整个变量,@号内的内容就被解析成一个独立的变量,而且因为它的最后有";},所以使反序列化成功结束。

参考链接:https://www.jianshu.com/p/3b44e72444c1

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注