[0CTF 2016]piapiapia
很有意思的一道题
访问页面之后是登录界面
尝试弱口令登录一下,无果
查看源代码之后也没有什么提示,扫描敏感目录,发现有源码泄露。
这里我用御剑没有扫出来源码泄露,可能跟扫描线程太快了有关,查看www.zip里面泄露的源代码
class.php里面定义了user和mysql两个类
config.php里面是服务器搭建环境的时候设置的参数,如果读者有自己本地搭建环境的经验就会知道,我们下载下来源码之后,还需要根据自己本地的环境进行相应的配置,比如说我们需要在config.php里面设置自己本地数据库的用户名和密码,这些在下载下来的config.php的源代码里面都是暂时空缺的。
所以题目环境docker下发的时候,一定也设置了自己本地的$flag的值,于是我们的目标就是需要读取服务器端config.php文件,就能够得到flag了。
在register.php里面,可以看到是注册一个用户,输入用户名和密码,接着跳转到index.php界面进行登录
在index.php里面我们输入用户名和密码进行登录,接着跳转到profile.php页面。
在此之前我们需要传递$profile的值
这里对我们输入的phone,email,nickname都进行了过滤,在源码的注释里面我已经进行了说明,很明显最后一个if语句的判断跟前两者有所不同,前两者如果phone为数组的话,匹配失败则为null,取反后就die,而第三个if当nickname为数组的时候,它不会匹配到非数字字母的值,也就为false,长度处使用数组strlen函数也会失效,返回NULL,则绕过了此处的if过滤。
所以对于输入的nickname的值我们是可控的。
再去看profile.php
可以看到这里对$profile的值进行了反序列化,接着依次读取,此时对于$photo有一个file_get_contents()文件读取函数,所以这里是我们破题的关键。
值得一提的是,在class.php的mysql类的定义中,过滤函数为
可以看出来将黑名单数组里面的值都换成了hacker
而我们唯一能够控制的变量则是之前说到的nickname,参考了很多师傅的WP之后,写一下这道题的主要知识点:
PHP序列化长度变化导致字符逃逸
首先, PHP反序列化中值的字符读取多少其实是由表示长度的数字控制的,而且只要整个字符串的前一部分能够成功反序列化,这个字符串后面剩下的一部分将会被丢弃
简单举几个例子大家就明白了
得到这个结果很正常
接着我们改变一点点
得到的结果变成了hello woxxx
我们可以看到,原来的字符串hello world内被填充了几个字符串,即xxx”;},在PHP进行反序列化时,由字符串初始位置向后读取8个字符,即使遇到字符串分解符单双引号也会继续向下读,此处读取到 woxxx ,而后遇到了正常的结束符”;},达成了正常反序列化的条件,反序列化结束,后面的 rld”;} 几个字符均被丢弃。
我们用另外一个例子来学习一下这个知识点的应用
可以看到bad_str函数会将序列化之后的单引号转换成为字符串no,实际上这里就已经有了长度的变化,因为单引号长度是1,而no字符串长度是2
接着,我们修改用户的签名
这里偷一张别的师傅的图,虽然输入的值不同,但是思想是相同的

在我们这里,则是想将hello world改变掉。
于是构造
输出的结果跟我们想要的是相同的,hello world变成了hhh
参考一下大佬博客里面对此的解释
再回到我在本地的例子上面,我们为了使hhh替换掉hello world,于是这一段是需要逃逸出来的字符串
长度为17,而单引号替换成no之后长度只是增加1,所以为了增加17个长度,我们需要17个单引号,这样才能够将逃逸字符串挤出原来的位置。
紧接着,17*no+test,一共是38个字符,所以在s处我们填写长度为38
最后的$fakes就为
所以在此处我们最终字符串替换成为了hhh
先闭合了一个变量的正确格式,又写入了一个变量的正确格式,最后闭合了一个反序列化的操作。该挤出的被挤出逃逸了,该丢弃的丢弃了,最后想要达成的目标也实现了。
于是我们再回归到题目里面来,因为我们最后是从数据库里面读取反序列化之后的结果,所以我们先在本地搭建序列化,看看序列化的格式之后编写相应的payload
可以看到,根据泄露的源码序列化之后的结果为
我们能够构造的是nickname,在这里我已经是传递数组给他了
我们需要将photo的值hello改变成config.php
根据之前的基础知识,本地的直接构造为:
需要逃逸的字符串为
长度为34,所以添加34个单引号,长度为34*2+4即72
可以看到本地的查看的文件已经修改为了config.php
我们在题目里面使用相同的思想
因为where转换成hacker会由5–>6,字符有一个增加,所以我们为了逃逸34个字符,就添加34*where
警告无伤大雅,因为我们传递的是数组类型的值,所以这里会有警告
源代码里面的base64编码就是config.php的base64编码,解码即可
可以看到成功读取了config.php,里面有flag的值
贴上参考的师傅的博客链接
__EOF__

本文链接:https://www.cnblogs.com/Cl0ud/p/12177095.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!