分析
入口是在app::run(),这里有创建http的请求实例,

随后在后面会有路由检查,从这里跟进函数routeCheck
。

在路由检查中会到路由类的check方法处,继续跟进。

在check中会有获取当前方法的method

下面在method中会获取var_method
这个伪变量,其实这个就是我们通过post传进的_method
,这里进入判断之后会将我们post的值当做Request类的方法调用,这里我们的poc是传入的__construct
,这样就会调用它的构造方法,并且参数是post数据。

继续跟进构造方法,这里的foreach会遍历所有变量,将存在的参数全部覆盖掉,在我们传入的参数中的filter,就把之前的覆盖了,并且在这里传入method为get的原因也是因为之前注册路由是get方法,所以这里要把请求的method覆盖成get,避免报错。

在这调用完成之后routeCheck
将返回method
赋值给dispatch
。之后会继续在run函数里面执行exec函数。由于type为method执行相应的分支。


而这里的param
方法能获取参数,并且和URL中的参数合并。这里得到的参数就是post数据中的get[]=dir

它的返回调用了input
方法,跟进input
。


input
最后将参数和filter
一起传入array_walk_recursive
中。其中参数中有我们传的dir
,而filter
通过getFilter
有我们传的system
。


在这之后调用的array_walk_recursive
会用filterValue
,来处理数据,在这之中用call_user_func
。

这里system
和dir
分别是filter和value中的值,凑在一起就触发命令执行。
这里是第一个poc的分析,而第二个poc比较类似,同样是利用input函数,这里利用的点是在param的$this->method(true)
中。
因为是true所以进入了server('REQUEST_METHOD')
,最后同样到input中,并且data是server数组,filter同样是system。

造成的效果都是命令执行。
复现


后记
在调试的过程中也算是学到了很多东西,比如vscode+xdebug的动态调试方案,特别的轻巧,功能点也很完善。关于在验证poc的时候其实出了一些小问题,那就是我的burp发送的post数据和header之前多了一个空行,也就是这个多的空行导致我的poc老是失败……这也是注意小的细节问题,只有在真正调试的时候才会被发现。
以后还是要多动手实践。接下来几天我会研究一点新的东西,拭目以待吧。