一道题目看php反序列化逃逸
——————原题出自2022强国杯ezpop_new 通过本地复现题目,观察几个类和定义的函数,PingUtils类中存在可执行命令的system函数,应该是pop链最后一环,再看定义的filter函数使用preg_replace将数组中的字符替换成nonono,但替换前后字符长短不一,判断考点是php反序列化逃逸 经过代码审计初步推断出调用顺序: Alice->Bob->Cindy->PingUtils 在Bob类中存在if判定,flag为真才可能去调用Cindy,而__wakeup方法在调用该类时将flag赋值为false,所以这里还涉及到一个wakeup方法的绕过,让序列化后的属性个数的值大于真实个数即可 先来构造一个简单的pop
1 | <?php |
O:5:"Alice":1:{s:1:"c";O:3:"Bob":2:{s:4:"flag";b:1;}}
成功调用了Bob并绕过了wakeup方法 然后再细看Bob类中的操作,首先cindy变量实例化了一个cindy类,cindy类的someone通过request方法提交,phone被定义。然后经过filter函数替换字符后调用cindy的call方法 我们先改一行代码提交一个someone把filter过滤后的序列化数据输出来方便思考后续逃逸 someone可控,在此处构造反序列化的逃逸,cindy的phone变量要改成PingUtils类,从而能够访问到PingUtils的call方法。同时PingUtils的call方法接收到someone的字符带入到system中执行。 按照这个思路我们再把代码中phone改成new PingUtils看一下生成的序列化数据是什么样 可以看到someone后的字符是这些: ";s:5:"phone";O:9:"PingUtils":0:{}}
一共是35个字符,要使这35个字符逃逸出去就要在filter函数替换的时候多出35个位置,一个flag替换成nonono多出两个位置,一个fopen替换成nonono多出1个位置,共需要17个flag字符和一个fopen字符,使用管道符拼接whoami命令测试(windows环境) payload: ?pop=O:5:%22Alice%22:1:{s:1:%22c%22;O:3:%22Bob%22:2:{s:4:%22flag%22;b:1;}}&someone=flagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagfopenwhoami";s:5:"phone";O:9:"PingUtils":0:{}}
成功执行