php unserialize
之前没怎么接触过PHP反序列化的问题,这两天碰巧做了一道往年的题,遇到了,算是初步了解了PHP反序列化的问题,记录一下解决思路
题目链接:https://buuoj.cn/login?next=%2Fchallenges%3F#%5B0CTF%202016%5Dpiapiapia
环境探测
PHP版本5.6 没有发现其他有用信息
用扫描器扫了一下发现了网站备份,下载下来。
1 |
|
1 | config.php |
阅读源码后发现其资料更新流程是这样的:
在update.php点击更新资料后,在本页面处理,经过正则表达式过滤后通过的话,在user类中的update_profile方法中执行序列化后的profile
$user->update_profile($username, serialize($profile));
跟进user->update_profile方法:
用户名和资料经过过滤器fileter过滤后直接丢给mysql更新,继续跟进filter
主要是正则替换。把危险字段替换为“hacker”。这里有问题。暂时不管,继续跟进。
顺利通过filter后则可顺利更新用户资料。
再看profile.php里面这句话:
$photo = base64_encode(file_get_contents($profile[‘photo’]));
file_get_contents 是不是想到了什么?伪协议?
我们想读取到的文件是config.php 因为里面已经提示了有flag字段。
接下来我们要做的是让file_get_contents()包含config.php这个文件
先自己尝试下替换文件名,失败了。
接下来考虑伪协议,也失败了。。
然后考虑反序列化的问题
首先明白什么是反序列化
个人理解反序列化就是把对象,变量,各种属性不一的文件通过一种形式的转换转换成字符串(序列化),并且还能通过该字符串还原该对象(反序列化)
一个例子就是ss导出配置的时候给他base64解密看看是不是序列化的思想呢2333
举个栗子
反序列化严格按照长度进行反序列化,如果长度改变的话可能反序列化失败。比如:
在反序列化之前,我把最后一个字符串加了一个d 但是前面的长度还是5没有变,所以反序列化失败了,报错。
还有一种情况:
通过自己构造的反序列化对象,可以修改对象的某些属性。
比如之前c的最后一个字符串为234,我们构造$c1=’a:3:{i:0;s:3:”123”;i:1;s:3:”abc”;i:2;s:5:”wdnmd”;}”;i:2;s:3:”234”;}’;
就把最后一个属性的值换成了wdnmd,后面原来的字符串会被忽略。起到了夹带私货的作用。
这道题我们想让photo的值为config.php,所以需要利用上面说的字符串逃逸的问题,将payload挤到后面去。
具体什么意思?
对nickname的内容进行构造,我们知道,序列化之后长度固定不变。就是S:后面的数字。但是问题就出现在他存在一个字符串替换,把where替换成hacker,使得字符串长度+1。那么问题来了,如何利用?
首先绕过正则表达式对nickename的判断,用数组就好。nickname[]
我们想传入的字符串为 “;}s:5:”photo”;s:10:”config.php”;} 总长度为34,所以我们需要写34个where加上我们想传入的字符串作为payload,总长度为204(包括34个where和想传入的字符串)
在经过序列化,过滤的过程中,所有的where被替换成和hacker,这样序列化后的s:204不变,nickname的值变成了34个hacker,并且成功的修改了photo的值为config.php
payload:wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere”;}s:5:”photo”;s:10:”config.php”;}
注意:
任何不正确的反序列化是会失败的。
In the end:
php unserialize的问题有很多,我只是学习到了其中的一个,等学习到了其他的问题继续整理、巩固下来。