点击此处获得更好的阅读体验
WriteUp来源
题目考点
变量覆盖
预包含
反序列化中的对象逃逸
解题思路
首先打开网页界面,看到source_code,点击就可以直接看到源码。
从上往下阅读代码,很明显的可以发现一个变量覆盖。至于这个覆盖怎么用,暂时还不知道,这是第一个考点。
往下看,可以看到我们可以令function为phpinfo来查看phpinfo,此时就可以看到我的第二个考点:
我在php.ini中设置了auto_prepend_file隐式包含了d0g3_f1ag.php,直接访问可以发现没有任何内容,说明我们需要读取这个文件的内容。
接着往下看代码,可以看到最终执行了一个file_get_contents
,从这个函数逆推回去$userinfo["img"]
的值,可以发现这个值虽然是我们可控的,但是会经过sha1加密,而我没有解密,导致无法读取任何文件。
此时需要把注意力转移到另外一个函数serialize
上,这里有一个很明显的漏洞点,数据经过序列化了之后又经过了一层过滤函数,而这层过滤函数会干扰序列化后的数据。
PS:任何具有一定结构的数据,如果经过了某些处理而把结构体本身的结构给打乱了,则有可能会产生漏洞。
先放payload:
1 | _SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}&function=show_image |
这里我令_SESSION[user]为flagflagflagflagflagflag,正常情况下序列化后的数据是这样的:
1 | a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";} |
而经过了过滤函数之后,序列化的数据就会变成这样:
1 | a:3:{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";} |
可以看到,user的内容长度依旧为24,但是已经没有内容了,所以反序列化时会自动往后读取24位:
会读取到上图的位置,然后结束,由于user的序列化内容读取数据时需要往后填充24位,导致后面function的内容也发生了改变,吞掉了其双引号,导致我们可以控制后面的序列化内容。
而php反序列化时,当一整段内容反序列化结束后,后面的非法字符将会被忽略,而如何判断是否结束呢,可以看到,前面有一个a:3,表示序列化的内容是一个数组,有三个键,而以{作为序列化内容的起点,}作为序列化内容的终点。
所以此时后面的";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";}
在反序列化时就会被当作非法字符忽略掉,导致我们可以控制$userinfo["img"]的值,达到任意文件读取的效果。
在读取完d0g3_f1ag.php
后,得到下一个hint,获取到flag文件名,此时修改payload读根目录下的flag即可。