前言
反序列化plus之pop链的构建,趁寒假还有点时间就继续学习下。
什么是pop链
在反序列化中,我们能控制的数据就是对象中的属性值,所以在PHP反序列化中有一种漏洞利用方法叫”面向属性编程”,即POP(Property Oriented Programming)。
在利用反序列化漏洞时,漏洞的利用点有时候并不会在魔术方法中,而是存在于普通方法中,这时候我们就要构建pop来逐步跟进调用函数,直到找到利用点。
例题理解
【极客大挑战2021】babyPOP
回顾一下去年极客大挑战这道POP题,先看代码:
1 | <?php |
审计代码,类a中定义了两个静态变量,均为flase,接着看利用点在类b的exec函数中,而要利用这个函数需要满足$Do_u_like_AFKL为true,因此定位到类d,而__invoke方法需要使用调用函数的方式调用一个对象,因此定位到类e,发现需要$Do_u_like_JiaRan为true才可以,最后定位到类c。
理清逻辑后,我们发现c与e之间没有直接的桥梁,因此我们需要自定义变量连接两者,构建payload:
1 | $c=new c(); |
这题利用反弹shell原理对b赋值即可。
[MRCTF2020]Ezpop
这是一道比较经典的pop链的题目,很适合做参考。
源代码:
1 | <?php |
同样审计代码进行分析,首先找到利用点,发现类Modifier中存在include函数,确认这里为利用点。接着发现我们想要执行这个利用点,就需要调用append这个方法,而要调用这个方法就需要触发__invoke方法,因此我们需要传入var的值。
而要触发__invoke方法,则需要类Test中的属性$p,但是要调用__get方法才可以,而调用__get方法则需要给在类Show中的str赋值类Test的对象,由于类Test中没有属性$source所以可以调用。因此,我们需要调用__toString方法,而要调用这个方法需要类Show的对象被当成字符串操作,因此要利用__wakeup方法,这个方法中$source属性被当成字符串去比较。
逻辑整理完,构建payload:
1 | <?php |
最后传参即可得到flag。
魔术方法总结
魔术方法这块在之前的博客也简单提到了,由于pop链的构造整个机制对魔术方法的运用还是有一定要求的,这里就再复习下:
- __construct(),类的构造函数
- __destruct(),类的析构函数
- __call(),在对象中调用一个不可访问方法时调用
- __callStatic(),用静态方式中调用一个不可访问方法时调用
- __get(),获得一个类的成员变量时调用
- __set(),设置一个类的成员变量时调用
- __isset(),当对不可访问属性调用isset()或empty()时调用
- __unset(),当对不可访问属性调用unset()时被调用。
- __sleep(),执行serialize()时,先会调用这个函数
- __wakeup(),执行unserialize()时,先会调用这个函数
- __toString(),类被当成字符串时的回应方法
- __invoke(),调用函数的方式调用一个对象时的回应方法
- __set_state(),调用var_export()导出类时,此静态方法会被调用。
- __clone(),当对象复制完成时调用
- __autoload(),尝试加载未定义的类
- __debugInfo(),打印所需调试信息
具体分析参考下面这几篇博客:
PHP之十六个魔术方法详解
PHP反序列化和魔术方法
总结
pop链的构建还是具有一定难度的,对链条的逻辑需要有准确的判断,还是需要做一些练习来巩固的。还剩原生方法那一块没看,之后找个时间稍微学下。