serVuln4 create_fucntion与可变函数
源码
|
POC
|
O:6:"Cancer":1:{s:3:"key";s:114:"a:2:{i:0;O:7:"GetFlag":2:{s:4:"code";s:16:"}system('ls');//";s:4:"func";s:15:"create_function";}i:1;s:6:"create";}";} |
注意:两个类实例化调用属性的顺序。
传入payload ,得到
Cancer::__destruct |
payload 被反序列化,触发Cancer 类的 destruct 方法,进而key 被反序列化,也就是unserialize(serialize(array($getflag, "create")))(); ,这段代码会调用 GetFlag::create 方法。
这是因为在 PHP 中,array($getflag, "create") 创建了一个包含两个元素的数组,第一个元素是 GetFlag 类的一个实例 $getflag,第二个元素是字符串 “create”。在 PHP 中,这样的数组可以被解释为一个回调函数,其中 $getflag 是要调用方法的对象,”create” 是要调用的方法名。
而array($getflag, "create")()与call_user_func(array($getflag, "create"))是等价的,可以看一个demo
|
回到题目,调用GetFlag::create 方法后,由于GetFlag类中存在$a('', $this->code); ,这里为了减小难度,直接提示create_function('', $this->code),考虑 create_function 函数的特性,这里会创建一个新的匿名函数,并将其函数体作为字符串传递给 eval() 函数。eval() 函数会执行这个字符串中的 PHP 代码。
PS:这也是create_function被移除的原因
对于"}system('chdir');//",这段代码以 } 开头,会导致 eval() 函数认为当前的函数体已经结束,然后执行后面的 system('chdir'); 代码,其中//并不是注释符的作用,而是为了防止"}system('chdir');" 被完整解析,导致语法错误,//可以用#、{代替,有兴趣可以测试一下这个demo
|
可变函数与create_function
引用自PHP手册:
- PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现回调函数等等
create_function通过执行代码字符串创建动态函数。该函数已自PHP 7.2.0起被废弃,并自PHP 8.0.0起被移除- 相关知识:
