GYCTF2020Easyphp
反序列化 字符串逃逸
题目打开是这样的,没什么东西,简单试了一下弱密码啥的,发现好像没有注入
然后扫描一下,发现了www.zip
打开看一下:
有lib.php login.php index.php update.php
index.php的:

导入了 lib.php,然后就是如果登陆成功会转入到 update.php
update.php:

判断,登陆成功才会有 flag .
再来看看 login.php:

对我们的数据进行了限制。
最后看看 lib.php:




这个是最核心的代码,可以看到 user 类 里面的 update() 函数 存在 unserialize()函数,可能会存在反序列化漏洞,跟进一下 getNewInfo()函数
获取到 POST 传过来的 age 和 nickname 参数,然后会进行一波序列化,会把 age和nickname 传到Info() 类 然后序列化,可以看到会经过safe()函数,会对字符进行一定的替换,这个时候可能就会导致漏洞,前后数据处理 不一致很容易造成漏洞(这里发生字符串逃逸,我们利用nickname来进行逃逸。
大致知道了漏洞的利用点,就是利用字符串逃逸来进行反序列化,这个时候就是需要构造 pop 链 ,来达到我们想要的目的。
和数据库查询交互的主要是dbCtrl 类的 login()函数,这里有一个简单的思路浮现,如果能利用pop链打出 admin的密码,然后以admin的身份登录就OK了。
怎么构造POP链?
之前的几次我都是逆推,从我们最终想要利用的那个点出发,一层一层往前推,这次我顺着出题人的思路,从前往后,index.php的源码分析之后,找不到可以利用的地方,我们从update.php 这里看起,会初始化一个user类,然后调用 user()的 update方法,然后对传入的参数进行序列化,然后反序列化。 顺着推的思路: 大致看一下有哪些魔法函数 : _destruct , to_string, _call 函数, 其实也就这三个,所以顺着“出题人”思路来想,肯定是大概率得利用到的,逻辑就很清晰了,很显然得通过 UpdateHelper类的 destruct 来 echo $sql ,这个时候如果我们控制 $sql 为 User 类 就会调用 to_string ,然后再想办法调用 _call,这里通过 nickname 调用一个不存在的方法就可以触发, 让 nickname 为 Info 类 ,Info类不存在 update函数,就会调用 call 函数了,这里再让CtrlCase等于dbCtrl类,然后age参数控制一下,就可以控制数据库查询语句了,我们改一下语句 select password,id from user where username=? 就可以打出admin的密码了。最终的POP链:

最后在 update.php 页面传 age=123&nickname=exp 即可
1.如果我们不利用字符串逃逸,我们输入进去的东西,你以为的pop链,仅仅只是它一个参数(这里是nickname参数)的值而已,没错,就是字符串而已,它反序列化时对应的也是一串字符串,造成不了任何影响,所以我们这里得利用字符串逃逸让它成为一个真正的类。
2.逃逸原理弄清楚了,然后对 ”;s:”CtrlCase”;和 } 进行说明:
} 是起到闭合的作用,”闭合 前面的”,然后;表示结束,这个没问题,但一开始我对多出地一个s:”CtrlCase”;,纠结了很久。
后来有回过头来看了看传参才看清楚,我们的age和nickname是传到了 Info 类里面,Info类 序列化 会有三个参数,一个是age,一个是nickname,一个是CtrlCase ,这里我们利用 字符串逃逸,构造了一个CtrlCase,并且让它对应是序列化的类,而不是字符串。
举个例子:
{s:2:”id”;N;s:7:”newinfo”;N;s:3:”sql”;O:4:”User”:3:
随便截取的序列化的一个例子,可以看到 id 的值 对应的是 字符串 s:7:”newinfo” 而 sql 对应的 O:4,可以看到sql对应的值是类,这个才能出发一系列的pop链。
