漏洞介绍
CNNVD编号:CNNVD-201812-489
nonecms的作者通过升级 thinkphp 框架的版本把漏洞修复了
查看 thinkphp/library/think/App.php
这个文件的修改历史可以发现
更新框架前是5.1.0
const VERSION = '5.1.0';
更新框架后是5.1.31
const VERSION = '5.1.31 LTS';
漏洞修复
漏洞出现在 NoneCMS/thinkphp/library/think/route/dispatch/Url.php
文件中的parseUrl方法里
// 解析模块 $module = $this->app->config('app_multi_module') ? array_shift($path) : null; if ($this->param['auto_search']) { $controller = $this->autoFindController($module, $path); } else { // 解析控制器 $controller = !empty($path) ? array_shift($path) : null; } // 解析操作 $action = !empty($path) ? array_shift($path) : null; // 解析额外参数 if ($path) { if ($this->app['config']->get('url_param_type')) { $var += $path; } else { preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) { $var[$match[1]] = strip_tags($match[2]); }, implode('|', $path)); } }
为了修复漏洞,thinkphp官方添加了新的代码
if ($this->param['auto_search']) { $controller = $this->autoFindController($module, $path); } else { // 解析控制器 $controller = !empty($path) ? array_shift($path) : null; } /**** 加入了这段代码 **** if ($controller && !preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) { throw new HttpException(404, 'controller not exists:' . $controller); } **** 加入了这段代码 ****/ // 解析操作 $action = !empty($path) ? array_shift($path) : null;
具体修改历史可以在以下链接找到
概括地说,就是把library/think/route/dispatch/Module.php
的代码移动到 library/think/route/dispatch/Url.php
$controller变量的校验代码经过多次改进之后,变成下面这个样子
if ($controller && !preg_match('/^[A-Za-z][\w|\.]*$/', $controller)) { throw new HttpException(404, 'controller not exists:' . $controller); }
[A-Za-z][\w|\.]*
这个正则表达式的含义是 $controller 的第一个字符是字母A-Za-z。 [\w|\.]
匹配 a-zA-Z0-9_ 和 .
。 例如可以匹配 a.b.abc123..
, 所以严格来说, 这个正则表达式不是特别准确 。
漏洞运行
如果上面这段 $controller 变量的校验代码去掉并访问下面类似的链接,就会复现之前的漏洞。
http://xxx.com/NoneCms/public/?s=index/\think\Request/input&filter=phpinfo&data=1
这时候变量 $controller
等于 \think\Request
当执行到文件 NoneCMS/thinkphp/library/think/Request.php
中的代码的时候, $filter = "phpinfo", $value = 1
private function filterValue(&$value, $key, $filters) { $default = array_pop($filters); foreach ($filters as $filter) { if (is_callable($filter)) { // 调用函数或者方法过滤 $value = call_user_func($filter, $value);
等于执行了以下代码,这样php运行环境的敏感信息就泄露了。适当构造URL参数就可以实现更多攻击和破解操作。
$filter = "phpinfo"; $value = 1; call_user_func($filter, $value);
总结
- 调用call_user_func函数时,要进行参数校验。
- 对于 HTTP GET 请求里的参数尽可能使用严格的正则表达式进行校验。

This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.