### 简要描述: YXCMS前台getshell,有条件,非鸡肋。 ### 详细说明: 0x00 介绍 YXcms是一款基于PHP+MySql开发的网站管理系统。采用轻量级MVC设计模式,使得系统更加小巧灵活,避免了使用大型框架构建系统的笨重;APP应用方式使系统各功能板块之间耦合更低,易于安装卸载;自定义表功能,使得网站数据结构设计更加灵活,方便自定义各种留言、报名等功能,也可以将图集、文章拓展成为其他例如:产品、下载等栏目;独特的图片处理功能可以将图片管理细致到每个像素;独特的分类算法,实现了栏目无限分类的同时,又避免了普通递归分类算法造成的系统资源消耗。 而从1.2.1.5版本开始,yxcms开始增设前台用户上传图片功能,给我们本次漏洞形成提供了一个条件。 0x01代码分析 //index.php ``` require( 'protected/core.php' ); ``` 直接看core.php 242行,调用了网址路由解析的函数urlRoute() ``` function urlRoute(){ $rewrite = config('REWRITE'); if( !empty($rewrite) ) { if( ($pos = strpos( $_SERVER['REQUEST_URI'], '?' )) !== false ){ parse_str( substr( $_SERVER['REQUEST_URI'], $pos + 1 ), $_GET ); } foreach($rewrite as $rule => $mapper){ $rule = ltrim($rule, "./\\"); if( false === stripos($rule, 'http://')){ $rule = $_SERVER['HTTP_HOST'].rtrim(dirname($_SERVER["SCRIPT_NAME"]),'/\\').'/'.$rule; } $rule = '/'.str_ireplace(array('\\\\', 'http://', '-', '/', '<', '>', '.'), array('', '', '\-', '\/', '(?<', ">[a-z0-9_%]+)", '\.'), $rule).'/i';...
### 简要描述: YXCMS前台getshell,有条件,非鸡肋。 ### 详细说明: 0x00 介绍 YXcms是一款基于PHP+MySql开发的网站管理系统。采用轻量级MVC设计模式,使得系统更加小巧灵活,避免了使用大型框架构建系统的笨重;APP应用方式使系统各功能板块之间耦合更低,易于安装卸载;自定义表功能,使得网站数据结构设计更加灵活,方便自定义各种留言、报名等功能,也可以将图集、文章拓展成为其他例如:产品、下载等栏目;独特的图片处理功能可以将图片管理细致到每个像素;独特的分类算法,实现了栏目无限分类的同时,又避免了普通递归分类算法造成的系统资源消耗。 而从1.2.1.5版本开始,yxcms开始增设前台用户上传图片功能,给我们本次漏洞形成提供了一个条件。 0x01代码分析 //index.php ``` require( 'protected/core.php' ); ``` 直接看core.php 242行,调用了网址路由解析的函数urlRoute() ``` function urlRoute(){ $rewrite = config('REWRITE'); if( !empty($rewrite) ) { if( ($pos = strpos( $_SERVER['REQUEST_URI'], '?' )) !== false ){ parse_str( substr( $_SERVER['REQUEST_URI'], $pos + 1 ), $_GET ); } foreach($rewrite as $rule => $mapper){ $rule = ltrim($rule, "./\\"); if( false === stripos($rule, 'http://')){ $rule = $_SERVER['HTTP_HOST'].rtrim(dirname($_SERVER["SCRIPT_NAME"]),'/\\').'/'.$rule; } $rule = '/'.str_ireplace(array('\\\\', 'http://', '-', '/', '<', '>', '.'), array('', '', '\-', '\/', '(?<', ">[a-z0-9_%]+)", '\.'), $rule).'/i'; if(preg_match($rule,$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],$matches)){ foreach($matches as $matchkey => $matchval){ if(('app' === $matchkey)){ $mapper = str_ireplace('<app>', $matchval, $mapper); }else if('c' === $matchkey){ $mapper = str_ireplace('<c>', $matchval, $mapper); }else if('a' === $matchkey){ $mapper = str_ireplace('<a>', $matchval, $mapper); } else { if( !is_int($matchkey) ) $_GET[$matchkey] = $matchval; } } $_REQUEST['r'] = $mapper; break; } } if(empty($_REQUEST['r']) && trim($_SERVER["REQUEST_URI"],'/')) $_REQUEST['nor']=true; } $route_arr = isset($_REQUEST['r']) ? explode("/", htmlspecialchars($_REQUEST['r'])) : array(); //用“/”来分割数组 $app_name = empty($route_arr[0]) ? DEFAULT_APP : strtolower($route_arr[0]); //来自用户输入 $controller_name = empty($route_arr[1]) ? DEFAULT_CONTROLLER : strtolower($route_arr[1]); $action_name = empty($route_arr[2]) ? DEFAULT_ACTION : $route_arr[2]; $_REQUEST['r'] = $app_name .'/'. $controller_name .'/'. strtolower($action_name); define('APP_NAME', $app_name); // 在此处定义一个APP_NAME define('CONTROLLER_NAME', $controller_name); define('ACTION_NAME', $action_name); } ``` 而后在244行调用函数appConfig()来加载app配置 ``` function appConfig($app){ static $appConfig = array(); //echo BASE_PATH . 'apps/' . $app . '/config.php'; if( !isset( $appConfig[$app]) ){ //如果存在文件webroot/apps/$app/config.php就包含进来 if( is_file(BASE_PATH . 'apps/' . $app . '/config.php') ){ $appConfig[$app] = require(BASE_PATH . 'apps/' . $app . '/config.php'); //包含截断,产生漏洞 }else{ $appConfig[$app] = array(); } } return $appConfig[$app]; } ``` 利用证明: poc: 环境:GPC=Off 0x01 前台注册一个账号 0x02 制作一个插入一句话木马的图片 0x03 上传头像 获得上传地址 [<img src="https://images.seebug.org/upload/201412/14152752028c55bb7efafbb82c23a8688372d78c.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/14152752028c55bb7efafbb82c23a8688372d78c.png) upload/member/image/20141214/thumb_1418542014.jpg 0x04 包含之,漏洞exploit构成。 http://192.168.163.128/yxcms/index.php?r=..\..\upload\member\image\20141214\thumb_1418542014.jpg%00 [<img src="https://images.seebug.org/upload/201412/14152909df2cd1961af0c02cf1d289c38c26268c.jpg" alt="1.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/14152909df2cd1961af0c02cf1d289c38c26268c.jpg) 0x05 解释 因为 ``` $route_arr = isset($_REQUEST['r']) ? explode("/", htmlspecialchars($_REQUEST['r'])) : array(); ``` 只是用/来分割参数r提交来的数据,但是我们知道\跟/所代表的功能是一样的,只要能用\来提交就能绕过这个过滤。 此外 ``` if( is_file(BASE_PATH . 'apps/' . $app . '/config.php') ){ $appConfig[$app] = require(BASE_PATH . 'apps/' . $app . '/config.php'); //包含截断,产生漏洞 } ``` 只是判断webroot/apps/$app/config.php是否存在,存在就包含 但是如果gpc=off的情况下 我们可以用thumb_1418542014.jpg%00截断后面的字符,那么is_file()检测的文件就是 webroot/apps/..\..\upload\member\image\20141214\thumb_1418542014.jpg,而这个文件就是我们刚才上传的带dirty code的图片,显然存在。漏洞形成。 该漏洞的唯一限制就是php的gpc开启与否,但是鉴于windows+php平台下,大部分默认没有开启gpc,还是有很大的用户量的。漏洞危害很大。 ### 漏洞证明: 0x00 介绍 YXcms是一款基于PHP+MySql开发的网站管理系统。采用轻量级MVC设计模式,使得系统更加小巧灵活,避免了使用大型框架构建系统的笨重;APP应用方式使系统各功能板块之间耦合更低,易于安装卸载;自定义表功能,使得网站数据结构设计更加灵活,方便自定义各种留言、报名等功能,也可以将图集、文章拓展成为其他例如:产品、下载等栏目;独特的图片处理功能可以将图片管理细致到每个像素;独特的分类算法,实现了栏目无限分类的同时,又避免了普通递归分类算法造成的系统资源消耗。 而从1.2.1.5版本开始,yxcms开始增设前台用户上传图片功能,给我们本次漏洞形成提供了一个条件。 0x01代码分析 //index.php ``` require( 'protected/core.php' ); ``` 直接看core.php 242行,调用了网址路由解析的函数urlRoute() ``` function urlRoute(){ $rewrite = config('REWRITE'); if( !empty($rewrite) ) { if( ($pos = strpos( $_SERVER['REQUEST_URI'], '?' )) !== false ){ parse_str( substr( $_SERVER['REQUEST_URI'], $pos + 1 ), $_GET ); } foreach($rewrite as $rule => $mapper){ $rule = ltrim($rule, "./\\"); if( false === stripos($rule, 'http://')){ $rule = $_SERVER['HTTP_HOST'].rtrim(dirname($_SERVER["SCRIPT_NAME"]),'/\\').'/'.$rule; } $rule = '/'.str_ireplace(array('\\\\', 'http://', '-', '/', '<', '>', '.'), array('', '', '\-', '\/', '(?<', ">[a-z0-9_%]+)", '\.'), $rule).'/i'; if(preg_match($rule,$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],$matches)){ foreach($matches as $matchkey => $matchval){ if(('app' === $matchkey)){ $mapper = str_ireplace('<app>', $matchval, $mapper); }else if('c' === $matchkey){ $mapper = str_ireplace('<c>', $matchval, $mapper); }else if('a' === $matchkey){ $mapper = str_ireplace('<a>', $matchval, $mapper); } else { if( !is_int($matchkey) ) $_GET[$matchkey] = $matchval; } } $_REQUEST['r'] = $mapper; break; } } if(empty($_REQUEST['r']) && trim($_SERVER["REQUEST_URI"],'/')) $_REQUEST['nor']=true; } $route_arr = isset($_REQUEST['r']) ? explode("/", htmlspecialchars($_REQUEST['r'])) : array(); //用“/”来分割数组 $app_name = empty($route_arr[0]) ? DEFAULT_APP : strtolower($route_arr[0]); //来自用户输入 $controller_name = empty($route_arr[1]) ? DEFAULT_CONTROLLER : strtolower($route_arr[1]); $action_name = empty($route_arr[2]) ? DEFAULT_ACTION : $route_arr[2]; $_REQUEST['r'] = $app_name .'/'. $controller_name .'/'. strtolower($action_name); define('APP_NAME', $app_name); // 在此处定义一个APP_NAME define('CONTROLLER_NAME', $controller_name); define('ACTION_NAME', $action_name); } ``` 而后在244行调用函数appConfig()来加载app配置 ``` function appConfig($app){ static $appConfig = array(); //echo BASE_PATH . 'apps/' . $app . '/config.php'; if( !isset( $appConfig[$app]) ){ //如果存在文件webroot/apps/$app/config.php就包含进来 if( is_file(BASE_PATH . 'apps/' . $app . '/config.php') ){ $appConfig[$app] = require(BASE_PATH . 'apps/' . $app . '/config.php'); //包含截断,产生漏洞 }else{ $appConfig[$app] = array(); } } return $appConfig[$app]; } ``` 利用证明: poc: 环境:GPC=Off 0x01 前台注册一个账号 0x02 制作一个插入一句话木马的图片 0x03 上传头像 获得上传地址 [<img src="https://images.seebug.org/upload/201412/14152752028c55bb7efafbb82c23a8688372d78c.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/14152752028c55bb7efafbb82c23a8688372d78c.png) upload/member/image/20141214/thumb_1418542014.jpg 0x04 包含之,漏洞exploit构成。 http://192.168.163.128/yxcms/index.php?r=..\..\upload\member\image\20141214\thumb_1418542014.jpg%00 [<img src="https://images.seebug.org/upload/201412/14152909df2cd1961af0c02cf1d289c38c26268c.jpg" alt="1.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/14152909df2cd1961af0c02cf1d289c38c26268c.jpg) 0x05 解释 因为 ``` $route_arr = isset($_REQUEST['r']) ? explode("/", htmlspecialchars($_REQUEST['r'])) : array(); ``` 只是用/来分割参数r提交来的数据,但是我们知道\跟/所代表的功能是一样的,只要能用\来提交就能绕过这个过滤。 此外 ``` if( is_file(BASE_PATH . 'apps/' . $app . '/config.php') ){ $appConfig[$app] = require(BASE_PATH . 'apps/' . $app . '/config.php'); //包含截断,产生漏洞 } ``` 只是判断webroot/apps/$app/config.php是否存在,存在就包含 但是如果gpc=off的情况下 我们可以用thumb_1418542014.jpg%00截断后面的字符,那么is_file()检测的文件就是 webroot/apps/..\..\upload\member\image\20141214\thumb_1418542014.jpg,而这个文件就是我们刚才上传的带dirty code的图片,显然存在。漏洞形成。 该漏洞的唯一限制就是php的gpc开启与否,但是鉴于windows+php平台下,大部分默认没有开启gpc,还是有很大的用户量的。漏洞危害很大。