主页 > 网络编程 > ThinkPHP 5.1框架结合RCE漏洞的深入分析(7)

ThinkPHP 5.1框架结合RCE漏洞的深入分析(7)

这里首先创建了一个闭包函数,并作为参数传入了add方法中。

将闭包函数注册为中间件,然后存入了$this->queue[‘route’]数组中。

然后会返回到App类, $response = $this->middleware->dispatch($this->request);执行middleware类中的dispatch方法,开始调度中间件。

使用call_user_func回调resolve方法,

使用array_shift函数将中间件(闭包函数)赋值给了$middleware,最后赋值给了$call变量。

当程序运行至call_user_func_array函数继续回调,这个$call参数是刚刚那个闭包函数,所以这时就会调用之前App类中的闭包函数。

中间件的作用官方介绍说主要是用于拦截或过滤应用的HTTP请求,并进行必要的业务处理。所以可以推测这里是为了调用闭包函数中的run方法,进行路由调度业务。

然后在闭包函数内调用了Dispatch类中的run方法,开始执行路由调度。

跟进exec方法。

可以看到,这里对我们要访问的控制器Test进行了实例化,我们来看下它的实例化过程。

将控制器类名$name和控制层$layer传入了parseModuleAndClass方法,对模块和类名进行解析,获取类的命名空间路径。

在这里如果$name类中以反斜线\开始时就会直接将其作为类的命名空间路径。此时$name是test,明显不满足,所以会进入到else中,从request封装中获取模块的值$module,然后程序将模块$module、控制器类名$name、控制层$layer再传入parseClass方法。

对$name进行了一些处理后赋值给$class,然后将$this->namespace、$module、$layer、$path、$class拼接在一起形成命名空间后返回。

到这我们就得到了控制器Test的命名空间路径,根据Thinkphp命名空间的特性,获取到命名空间路径就可以对其Test类进行加载。

F7继续调试,返回到了刚刚的controller方法,开始加载Test类。

加载前,会先使用class_exists函数检查Test类是否定义过,这时程序会调用自动加载功能去查找该类并加载。

加载后调用__get方法内的make方法去实例化Test类。

这里使用反射调用的方法对Test类进行了实例化。先用ReflectionClass创建了Test反射类,然后 return $reflect->newInstanceArgs($args); 返回了Test类的实例化对象。期间顺便判断了类中是否定义了__make方法、获取了构造函数中的绑定参数。

然后将实例化对象赋值赋给$object变量,接着返回又赋给$instance变量。

继续往下看。

这里又创建了一个闭包函数作为中间件,过程和上面一样,最后利用call_user_func_array回调函数去调用了闭包函数。

在这个闭包函数内,主要做了4步。

1.使用了is_callable函数对操作方法和实例对象作了验证,验证操作方法是否能用进行调用。

2.new ReflectionMethod创建了Test的反射类$reflect。

3.紧接着由于url_param_type默认为0,所以会调用param方法去请求变量,但是前面debug开启时已经获取到了并保存进了Request类对象中的param变量,所以此时只是从中将值取出来赋予$var变量。

4.调用invokeReflectMethod方法,并将Test实例化对象$instance、反射类$reflect、请求参数$vars传入。

这里调用了bindParams方法对$var参数数组进行处理,获取了Test反射类的绑定参数,获取到后将$args传入invokeArgs方法,进行反射执行。

然后程序就成功运行到了我们访问的文件(Test)。

运行之后返回数据结果,到这里路由调度的任务也就结束了,剩下的任务就是响应输出了,将得到数据结果输出到浏览器页面上。

说点什么吧
  • 全部评论(0
    还没有评论,快来抢沙发吧!