网安 | 反序列化POP调用链构造一
一、什么是POP
POP即:面向属性编程(Property-Oriented Programing)常用于上层语言构造特定调用链的方法,是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链。在控制代码或者程序的执行流程后就能够使用这一组调用链做一些工作了。
一般的序列化攻击都在PHP魔术方法中出现可利用的漏洞,因为自动调用触发漏洞,但如果关键代码没在魔术方法中,而是在一个类的普通方法中。这时候就可以通过构造POP链寻找相同的函数名将类的属性和敏感函数的属性联系起来。
二、PHP漏洞代码
请通过反序列化操作,执行任意PHP命令。
三、POP调用链分析
1、确定终点
经过详细分析,目标调用存在于Tiger类的boss方法中,只要能够构造出boss方法的参数值为一条序列化字符串的PHP代码,即可完成。
2、寻找起点
通常反序列化过程中,必然会被自动调用的是__wakeup 和 __destruct
两个魔术方法,所以寻找上述代码中的起点,发现只有在Monkey类中存在__wakeup
,那么就暂时先以Monkey类作为起点,进行反序列化操作,但是是否能达到终点并不完全确定,如果最终无法到达终点,那么我们就必须要继续寻找新的起点,或者是评估调用链是否正确。
3、确定$this->head
在Monkey类的__wakeup
魔术方法中,使用了preg_match函数进行正则匹配,也就意味着第二个参数 $this->head
必须是一个字符串。从Monkey类中可以看到,$this->head
的值可以来源于构造方法,默认值为 Zoo,但是这样使用显然不可能,因为反序列化的时候,是不会调用构造方法的。那么所以只能换一个方向来思考,$this->head如果是一个对象呢,当把一个对象当成字符串处理时,会触发__toString魔术方法,这条路也许可行。
4、确定__toString所在类
现在有两个对象有tostring方法,分别是Elephant和Tiger,选择哪个呢,我们的目的是进入boss函数执行命令,可以看到Tiger的tostring方法只是返回一个变量没啥用,所以就选择让$this->head = new Elephant();
,此时会执行$this->nice->nose;
5、确定$this->nice
在Elephant的构造方法中,也存在对$nice的赋值,但是这类操作并没有实际价值,因为我们的目标是要想办法进行跳转,要一步一步跳转到别的类当中去执行代码,进而最终到达终点。目前还剩下Tiger的__invoke
和Lion的__get
没有进行跳转和调用,那么首先需要知道这两个魔术方法的触发条件:
(1)__invoke:当以函数方式调用对象时被调用,也就是类似:$a = new A(); $a();
这种调用方式时触发
(2)__get:读取不可访问或不存在属性时被调用
那么我们来分析一下,$this->nice
为哪个对象时,可以继续往下走。显然,此处不可能有条件能够触发到__invoke
,那么只能选择触发__get
,于是令$this->nice = new Lion()
,而Lion类并没有属性nose,所以完成对Lion类的__get
的触发
6、确定$this->tail
当跳转到Lion类的__get
方法时,此时我们看到两个特征,第一:在返回一个函数,那么这很有可能为下一步准备以函数方式调用对象做了铺垫,即可以触发Tiger类的__invoke
方法,目前看起来也许前面的POP正确性比较高。第二:需要确定$this->tail
的值,那么按照这个设计来看的话,此处应该令$this->tail = new Tiger();
是很有可能正确的。这个时候$function
就是Tiger对象,而下一步的代码return $function();
恰好可以印证这一点,实现了对象的函数式调用,进而触发Tiger类的__invoke
魔术方法。
7、确定$this->var
进到Tiger类的__invoke
魔术方法中时,直接看到了调用$this->boss()
方法,已经快到终点了,所以此时,只需要确定$this->var
的值便可以完成调用链的构造了,此时问题变简单了,只需要令$this->var = phpinfo();
即可完成构造。
8、以终为始
上述分析过程,是以起点开始的,而往往起点通向终点的过程并不一定非常顺利,所以也可以将分析过程反过来,以终点开始,逐步推向起点,效率也许会更高。如果倒推,顺推都是一条路径,那么足以说明POP链是完全正确的。
四、确定POC
五、总结
(1)先要确定起点和终点,如果起点有多个,那么就去尝试最有可能进行相互跳转的一个,起点和终点无法确定,POP链不可能成功。
(2)一定要牢记不同的魔术方法的自动触发条件,如果不太熟悉,则做实验证明,然后理解它。
(3)自动触发的跳转过程,会不停地给类变量(属性)赋值,一定要知道该赋什么样的值,通常的值都不会是普通类型,而是对象。
(4)POP链的分析和构造过程,可以完全忽略非魔术方法或也链条无关的方法和属性。
(5)POP的核心在于属性,而不是方法,序列化和反序列化的核心也在属性,而不是方法,所以方法对我们构造POC是无意义的。