漏洞流程分析
- 入口文件
App.php中的run(),实例化了一个$request对象传给了routeCheck()
- 跟进
routeCheck(),查看路由检测规则
- 跟进
check(),$method通过$request->method()获得,$rules根据$method获得不同的路由规则
- 跟进
method(),外部传入的Config::get('var_method')可控,其中var_method是表单请求类型伪装变量,传入_method即可进入判断。$_POST['_method']的值赋值给$this->method,然后动态调用$this->{$this->method}($_POST)。这意味着可以调用该类任意函数并以$_POST作为第一个参数。如果动态调用__construct函数,则会导致代码执行

- 在
Request类的构造方法中,$options可控,因此可以覆盖该类的任意属性。其中$this->filter保存着全局过滤规则
- payload种用的路由是
captcha,他的路由规则为get。因此需要让$this->method返回值为get,所以payload中有个method=get,然后才会取出self::$rules[$method]的值给$rules
- 继续查看入口文件的路由检测之后,可以看到执行了
exec()
- 在
exec()中查看method
- 跟进
param(),$this->param通过array_merge将当前请求参数和URL地址中的参数合并。
- 跟进
input(),该方法用于对请求中的数据即接收到的参数进行过滤,而过滤器通过$this->getFilter获得
- 跟进
getFilter(),$this->filter为system,回到input,因为data为数组,因此可以进入if条件调用array_walk_recursive($data, [$this, 'filterValue'], $filter),对$data中的每一个值调用filterValue函数
- 跟进
filterValue(),间接调用call_user_func,且两个参数可控,造成RCE
1 | ?s=captcha |
payload:
1 | /home/index.php?s=/home/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls -l |
5.0.0-5.0.24
1 | index.php?s=captcha |
