ThinkPHP 5.0 低版本反序列化利用链
前言
背景
日常渗透测试中,ThinkPHP低版本的站点虽然很少,但是总会有的,之前有大佬公开5.0.*的利用链,是适合中高版本的ThinkPHP框架,由于一些代码的改动,导致在某些地方并不能兼容所有的版本。
比如:
在5.0.16版本以下,HasOne类的getRelation的触发点removeWhereField方法未被调用。
在5.0.11版本以下,model类得三目运算符处的出发点不存在。
在5.0.4版本以下,触发的位置又有所不同。
本文将对已知反序列化利用链进行分析,并对比新老版本差异,构造属于老版本的利用链。
测试版本
- ThinkPHP v5.0.0-5.0.3
POC分析
已知利用链
Thinkphp5.0反序列化链在Windows下写文件的方法
上面对反序列化进行了分析,并构造出了适合windows和linux的稳定poc
个人认为核心触发点是output类得__call方法,调用block方法去完成文件的写入操作。
尝试去看了下其他的终点,暂未找到更好的利用方式。
经过对比,5.0.24版本的__call方法之后的节点与5.0.0版本的并无差异。
所以需要构造的新的入口点以及中间的跳转节点。
对比差异
原poc链
秉承着代码向下兼容的原则,适用于高版本的不一定适用低版本,但是这个很奇葩,向上也不兼容。
首先来看看原poc链条中其实有两处可以触发output类得__call方法。
第一种
自然是大家都说的三目运算符处,触发的魔术方法,$this->append是可控的,所以name参数是可控的。注意需要满足以下条件
流程跟踪
定义append未数组,值为getError
直接进入else分支
this->error设置为HasOne类,modelRelation就是可控的,进入getRelationData方法
此处判断条件满足,即可进入三目运算,已尝试,可行,poc自行构造,网上的poc有不少是利用的下面的第二种方法触发的
第二种
接上图,他们构造的poc没能完成if语句的判断,最终进入了else分支,如果方法存在,则调用getRelation方法,由于modelRelation参数是可控的,所以可调用任意类的getRelation方法,找到HasOne类的getRelation方法
差异
在旧版本中,以上两处触发的方式均不可用
如下图,此版本无三目运算符的判断
getAttr方法种倒是调用了getRelation方法,但是有个神判断,我过不去
所以,以上两条利用链均不可使用,需要找其他的利用链,大家的入口点都是windows类得析构方法,然后触发__toString方法,此路不通,需要找其他的入口点以及节点,查了查析构方法,还剩三个,挨个看就是了
构造利用链
寻找入口点
找到入口点为Process类的析构方法,跟进
调用了stop方法
构造中间节点
跟进stop方法
此处需要跳过第一处的判断,跟进isRunning方法,很简单
第二处的判断可控,进入close方法,跟进
此处可直接触发__call方法
但是在调用block方法后,由于block需要一个字符型的参数值,而我们没有进行传参,所以会抛出需要参数值的异常
所以需要在增加中间节点,找到了这么一处,Relation类得__call方法
上面类可控并且参数值可控,算是挺完美的触发点了
继续调用output类得__call方法,即可完成文件写入操作
完整的流程图不在画了
构造POC
测试代码
虽然抛出致命错误,但并不影响文件生成
POC
1 | <?php |
END
由于在后续版本中Relation重构,且成为了抽象类,所以此方法无法向上兼容,仅作学习参考
改变其中的某些节点,可覆盖5.0.4-5.0.24版本