Thinkphp5.0.x命令执行
【1】漏洞技术细节(涉及代码段、原理等)
漏洞根源利用函数:
ReflectionMethod可执行已存在类中的函数,->invokeArgs能接受参数
ReflectionFunction可反射执行php中任何函数,->invokeArgs能接受参数
在于call_user_func()
把第一个参数作为回调函数调用
如果两个参数都可控,即可命令执行,如下:
可控参数传入方式:
var_pathinfo的默认配置为s,可利用$_GET['s']来传递路由信息:
入口文件为public/index.php,调用了thinkphp/start.php
跟进start.php:
调用了App类中的静态方法run(),跟进run():
增加刚进入run函数时的断点,此时get到的变量如下:
在run函数中,会进入routeCheck函数进行URL路由检测,传入参数为 $request和$config
$request::instance = think\Request[35]
...
$request::hook = array[0]
$request->method = <null>
$request->domain = <null>
$request->url = <null>
$request->baseUrl = <null>
$request->baseFile = <null>
$request->root = <null>
$request->pathinfo = <null>
$request->path = <null>
$request->routeInfo = array[0]
$request->env = <null>
$request->dispatch = array[0]
$request->module = <null>
$request->controller = <null>
$request->action = <null>
$config是应用的相关配置:
$config["app_host"] = <string>
$config["app_debug"] = (bool) 0
$config["app_trace"] = (bool) 0
$config["app_status"] = <string>
$config["app_multi_module"] = (bool) 1
$config["auto_bind_module"] = (bool) 0
$config["root_namespace"] = array[0]
$config["extra_file_list"] = array[1]
...
$config["default_return_type"] = (string) html
$config["default_ajax_return"] = (string) json
$config["default_jsonp_handler"] = (string) jsonpReturn
$config["var_jsonp_handler"] = (string) callback
$config["default_timezone"] = (string) PRC
$config["lang_switch_on"] = (bool) 0
跟进routeCheck():
首先会执行$path = $request->path();
进入path函数中:
$suffix=html
再进入pathinfo函数:
通过Config::get方法获取到var_pathinfo的对应值为s,然后即为$_GET[‘s’]
得到$pathinfo = (string) index/\think\app/invokefunction
return 返回的值为 $this->path = (string) index/\think\app/invokefunction
因此routeCheck中的 $path为(string) index/\think\app/invokefunction
然后设置$result=false;
进行完$result = Route::check($request, $path, $depr, $config['url_domain_deploy']);后观察到值仍为false,因此再往下进入了parseUrl()函数进行path的解析,传入参数为:
( $path=index/\think\app/invokefunction , $depr=”/” , $config[‘url_domain_deploy’] )
此时调试栈情况如下:
跟进parseUrl()函数中:
执行$url = str_replace($depr, '|', $url); 后 $url = (string) index|\think\app|invokefunction
将$url再作为参数传入parseUrlPath进行处理,返回为以 / 分割开的数组
return [$path, $var];
执行$module = Config::get('app_multi_module') ? array_shift($path) : null;
后直接跳到了$controller = !empty($path) ? array_shift($path) : null;
然后为$action = !empty($path) ? array_shift($path) : null;
把$route封装后:
return ['type' => 'module', 'module' => $route]; 返回解析完的url数组
回到routeCheck中:
回到run函数:
执行$data = self::exec($dispatch, $config);时用到了返回的数组,进入exec函数:
type为module,进入APP.php/module函数中:
此时调试栈的情况如下:
执行完$module = strip_tags(strtolower($result[0] ?: $config['default_module']));后:
之后获取控制器和操作:
本次修复便在这里进行了过滤,对控制器进行正则匹配
获取到的各个值为:
// 设置当前请求的控制器、操作
$request->controller(Loader::parseName($controller, 1))->action($actionName);
继续执行如下初始化:
$instance = Loader::controller(
$controller,
$config['url_controller_layer'],
$config['controller_suffix'],
$config['empty_controller']
);
Loader::controller用于 实例化(分层)控制器
执行完后对应$instance的值如下:
is_callable验证think\app中存在invokefunction方法,进入if语句
[ is_callable() 函数验证变量的内容能否作为函数调用 ]
进入invokeMethod中:
此时调试栈情况如下:
传入的参数值如下:
执行完反射类创建后:$reflect = new \ReflectionMethod($class, $method[1]);
$args = self::bindParams($reflect, $vars); 获取POC中的余下的参数function 、vars的值
下面执行$reflect->invokeArgs函数,在ReflectionMethod类中此函数作用是使用数组方法给函数传递参数,并执行函数(由于要选择类才能执行函数,因此要借助invoke中的
ReflectionFunction函数来达到可以执行任意函数,从而传入要执行的函数名和参数)
最终借助invokeFunction,跟进:
执行完赋值操作后各变量值如下:
因此最终执行的为call_user_func_array函数,通过数组方式传入的参数为phpinfo,到这一步执行完后,就已经完成了命令的执行。
Example #1 ReflectionFunction::invokeArgs() example
<?php
function title($title, $name)
{
return sprintf("%s. %s\r\n", $title, $name);
}
$function = new ReflectionFunction('title');
echo $function->invokeArgs(array('Dr', 'Phil'));
?>
以上例程会输出:
Dr. Phil
因此把call_user_func()以及要执行的函数A和A所需参数一并传入ReflectionFunction中,即可执行
call_user_func() - 把第一个参数作为回调函数调用
所以第一个参数var[0]可以传要执行函数A,第二个var[1]可以传A函数需要的参数
【2】实验执行情况
【3】修复方法
thinkphp/library/think/App.php 类的module方法的获取控制器的代码后面加上:
if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) { throw new HttpException(404, 'controller not exists:' . $controller);
}
【4】参考文档/链接
https://www.cnblogs.com/backlion/p/10106676.html
https://www.cnblogs.com/st404/p/10245844.html