method()函数主要用于请求方法的判断,var_method没有通过,为可控参数,通过外部传入,thinkphp支持配置“表单伪装变量”,var_method在在外部的可控参数表现为_method:
由于var_method没有做任何过滤,我们可以通过控制_method参数的值来动态调用Request类中的任意方法,通过控制$_POST的值来向调用的方法传递参数。由上可知,漏洞存在于method()函数中,我们就需要寻找该函数的调用链,来构造POC。
第一个构造链在__construct()构造方法中,该方法如下:
函数中对$option数组进行遍历,当$option的键名为该类属性时,则将该类同名的属性赋值为$options中该键的对应值。因此可以构造请求如下,来实现对Request类属性值的覆盖,例如覆盖filter属性。filter属性保存了用于全局过滤的函数。
再上一个漏洞分析过程中,我们跟踪到了路由检查self::routeCheck 函数,在过程中,会进入到thinkphp/library/think/Route.php文件中的check()函数,函数中调用了method()方法,并将函数执行结果转换为小写后保存在$method变量。在调用构造函数覆盖变量时,可以直接覆盖method,这样上面的$method = strtolower($request->method()); 的$method最终的值就可以被控制了。
在该函数中,调用了method()函数,在该函数中,就将进行变量覆盖:
通过调用构造函数__construct(),最终将请求参数保存到input参数。
在进行routecheck后,已完成了第一部分调用链,实现了变量覆盖,接下来就是要实现变量覆盖后的代码执行,具体调用链如下:
返回到App.php文件中的run()函数,接着进入到exec()函数中,然后进入到module()函数中,最终进入到了invokeMethod()函数,
从invokeMethod()函数中进入到bindParams()函数,然后进入到param()函数:
然后最终调用到input()函数:
最终我们根据array_walk_recursive()函数,进入到了filterValue()函数:
最终,通过回调函数call_user_func执行了代码,整个调用链如上所示。
转载:https://www.freebuf.com/vuls/249178.html