[0CTF 2016]piapiapia
万能密码尝试无果后,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
所以我们使用34个where逃逸
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解析成一整个变量,@号内的内容就被解析成一个独立的变量,而且因为它的最后有";},所以使反序列化成功结束。