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

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

4.3.5 响应输出及应用结束

这一小节会对之前得到的数据结果进行响应输出并在输出之后进行扫尾工作结束应用程序运行。在响应输出之前首先会构建好响应对象,将相关输出的内容存进Response对象,然后调用Response::send方法将最终的应用返回的数据输出到页面。

继续调试,来到autoResponse方法,这个方法程序会来回调用两次,第一次主要是为了创建响应对象,第二次是进行验证。我们先来看第一次,

此时$data不是Response类的实例化对象,跳到了elseif分支中,调用Response类中的create方法去获取响应输出的相关数据,构建Response对象。

执行new static($data, $code, $header, $options);实例化自身Response类,调用__construct构造方法。

可以看到这里将输出内容、页面的输出类型、响应状态码等数据都传递给了Response类对象,然后返回,回到刚才autoResponse方法中

到此确认了具体的输出数据,其中包含了输出的内容、类型、状态码等。

上面主要做的就是构建响应对象,将要输出的数据全部封装到Response对象中,用于接下来的响应输出。

继续调试,会返回到之前Dispatch类中的run方法中去,并将$response实例对象赋给$data。

紧接着会进行autoResponse方法的第二次调用,同时将$data传入,进行验证。

这回$data是Response类的实例化对象,所以将$data赋给了$response后返回。

然后就开始调用Response类中send方法,向浏览器页面输送数据。

这里依次向浏览器发送了状态码、header头信息以及得到的内容结果。

输出完毕后,跳到了appShutdown方法,保存日志并结束了整个程序运行。

4.4 流程总结

上面通过动态调试一步一步地对URL解析的过程进行了分析,现在我们来简单总结下其过程:

首先发起请求->开始路由检测->获取pathinfo信息->路由匹配->开始路由解析->获得模块、控制器、操作方法调度信息->开始路由调度->解析模块和类名->组建命名空间>查找并加载类->实例化控制器并调用操作方法->构建响应对象->响应输出->日志保存->程序运行结束

五、漏洞分析及POC构建

相信大家在看了上述内容后,对Thinkphp这个框架应该有所了解了。接下来,我们结合最近一个思路比较好的RCE漏洞再来看下。为了更好地理解漏洞,我通过以POC构造为导引的方式对漏洞进行了分析,同时以下内容也体现了我在分析漏洞时的想法及思路。

在/thinkphp/library/think/Container.php 中340行:

在Container类中有个call_user_func_array回调函数,经常做代码审计的小伙伴都知道,这个函数非常危险,只要能控制$function和$args,就能造成代码执行漏洞。

如何利用此函数?

通过上面的URL路由分析,我们知道Thinkphp可由外界直接控制模块名、类名和其中的方法名以及参数/参数值,那么我们是不是可以将程序运行的方向引导至这里来。

如何引导呢?

要调用类肯定需要先将类实例化,类的实例化首先需要获取到模块、类名,然后解析模块和类名去组成命名空间,再根据命名空间的特性去自动加载类,然后才会实例化类和调用类中的方法。

我们先对比之前正常的URL试着构建下POC。

构建过程中,会发现几个问题。

1.模块应该指定什么,因为Container类并不在模块内。

2.模块和类没有联系,那么组建的命名空间,程序如何才能加载到类。

先别着急,我们先从最开始的相关值获取来看看(获取到模块、类名),此过程对应上面第四大节中的4.3.3路由解析中。

app_multi_module为true,所以肯定进入if流程,获取了$module、$bind、$available的值。在红色框处如果不为true,则会直接报错结束运行,所以此处需要$module和$available都为True。而$available的值一开始就被定义为False,只有在后续的3个if条件中才会变为true。

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