当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2014-086990

漏洞标题:ECSHOP存在XSS直打管理后台

相关厂商:ShopEx

漏洞作者: 路人甲

提交时间:2014-12-13 02:17

修复时间:2015-01-19 02:18

公开时间:2015-01-19 02:18

漏洞类型:xss跨站脚本攻击

危害等级:高

自评Rank:10

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-12-13: 细节已通知厂商并且等待厂商处理中
2014-12-18: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2015-02-11: 细节向核心白帽子及相关领域专家公开
2015-02-21: 细节向普通白帽子公开
2015-03-03: 细节向实习白帽子公开
2015-01-19: 细节向公众公开

简要描述:

N久了,你们是修还是不修啊?这么蛋疼的一个漏洞.

详细说明:

先看admin_logs.php代码

define('IN_ECS', true);
require(dirname(__FILE__) . '/includes/init.php');
/* act操作项的初始化 */
if (empty($_REQUEST['act']))
{
$_REQUEST['act'] = 'list';
}
else
{
$_REQUEST['act'] = trim($_REQUEST['act']);
}
/*------------------------------------------------------ */
//-- 获取所有日志列表
/*------------------------------------------------------ */
if ($_REQUEST['act'] == 'list')
{
/* 权限的判断 */
admin_priv('logs_manage');
$user_id = !empty($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
$admin_ip = !empty($_REQUEST['ip']) ? $_REQUEST['ip'] : '';
$log_date = !empty($_REQUEST['log_date']) ? $_REQUEST['log_date'] : '';
/* 查询IP地址列表 */
$ip_list = array();
$res = $db->query("SELECT DISTINCT ip_address FROM " .$ecs->table('admin_log'));
while ($row = $db->FetchRow($res))
{
$ip_list[$row['ip_address']] = $row['ip_address'];
}
$smarty->assign('ur_here', $_LANG['admin_logs']);
$smarty->assign('ip_list', $ip_list);
$smarty->assign('full_page', 1);
$log_list = get_admin_logs();
$smarty->assign('log_list', $log_list['list']);
$smarty->assign('filter', $log_list['filter']);
$smarty->assign('record_count', $log_list['record_count']);
$smarty->assign('page_count', $log_list['page_count']);
$sort_flag = sort_flag($log_list['filter']);
$smarty->assign($sort_flag['tag'], $sort_flag['img']);
assign_query_info();
$smarty->display('admin_logs.htm');
}
/*------------------------------------------------------ */
//-- 排序、分页、查询
/*------------------------------------------------------ */
elseif ($_REQUEST['act'] == 'query')
{
$log_list = get_admin_logs();
$smarty->assign('log_list', $log_list['list']);
$smarty->assign('filter', $log_list['filter']);
$smarty->assign('record_count', $log_list['record_count']);
$smarty->assign('page_count', $log_list['page_count']);
$sort_flag = sort_flag($log_list['filter']);
$smarty->assign($sort_flag['tag'], $sort_flag['img']);
make_json_result($smarty->fetch('admin_logs.htm'), '',
array('filter' => $log_list['filter'], 'page_count' => $log_list['page_count']));
}
/*------------------------------------------------------ */
//-- 批量删除日志记录
/*------------------------------------------------------ */
if ($_REQUEST['act'] == 'batch_drop')
{
admin_priv('logs_drop');
$drop_type_date = isset($_POST['drop_type_date']) ? $_POST['drop_type_date'] : '';
/* 按日期删除日志 */
if ($drop_type_date)
{
if ($_POST['log_date'] == '0')
{
ecs_header("Location: admin_logs.php?act=list\n");
exit;
}
elseif ($_POST['log_date'] > '0')
{
$where = " WHERE 1 ";
switch ($_POST['log_date'])
{
case '1':
$a_week = gmtime()-(3600 * 24 * 7);
$where .= " AND log_time <= '".$a_week."'";
break;
case '2':
$a_month = gmtime()-(3600 * 24 * 30);
$where .= " AND log_time <= '".$a_month."'";
break;
case '3':
$three_month = gmtime()-(3600 * 24 * 90);
$where .= " AND log_time <= '".$three_month."'";
break;
case '4':
$half_year = gmtime()-(3600 * 24 * 180);
$where .= " AND log_time <= '".$half_year."'";
break;
case '5':
$a_year = gmtime()-(3600 * 24 * 365);
$where .= " AND log_time <= '".$a_year."'";
break;
}
$sql = "DELETE FROM " .$ecs->table('admin_log').$where;
$res = $db->query($sql);
if ($res)
{
admin_log('','remove', 'adminlog');
$link[] = array('text' => $_LANG['back_list'], 'href' => 'admin_logs.php?act=list');
sys_msg($_LANG['drop_sueeccud'], 1, $link);
}
}
}
/* 如果不是按日期来删除, 就按ID删除日志 */
else
{
$count = 0;
foreach ($_POST['checkboxes'] AS $key => $id)
{
$sql = "DELETE FROM " .$ecs->table('admin_log'). " WHERE log_id = '$id'";
$result = $db->query($sql);
$count++;
}
if ($result)
{
admin_log('', 'remove', 'adminlog');
$link[] = array('text' => $_LANG['back_list'], 'href' => 'admin_logs.php?act=list');
sys_msg(sprintf($_LANG['batch_drop_success'], $count), 0, $link);
}
}
}
/* 获取管理员操作记录 */
function get_admin_logs()
{
$user_id = !empty($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
$admin_ip = !empty($_REQUEST['ip']) ? $_REQUEST['ip'] : '';
$filter = array();
$filter['sort_by'] = empty($_REQUEST['sort_by']) ? 'al.log_id' : trim($_REQUEST['sort_by']);
$filter['sort_order'] = empty($_REQUEST['sort_order']) ? 'DESC' : trim($_REQUEST['sort_order']);
//查询条件
$where = " WHERE 1 ";
if (!empty($user_id))
{
$where .= " AND al.user_id = '$user_id' ";
}
elseif (!empty($admin_ip))
{
$where .= " AND al.ip_address = '$admin_ip' ";
}
/* 获得总记录数据 */
$sql = 'SELECT COUNT(*) FROM ' .$GLOBALS['ecs']->table('admin_log'). ' AS al ' . $where;
$filter['record_count'] = $GLOBALS['db']->getOne($sql);
$filter = page_and_size($filter);
/* 获取管理员日志记录 */
$list = array();
$sql = 'SELECT al.*, u.user_name FROM ' .$GLOBALS['ecs']->table('admin_log'). ' AS al '.
'LEFT JOIN ' .$GLOBALS['ecs']->table('admin_user'). ' AS u ON u.user_id = al.user_id '.
$where .' ORDER by '.$filter['sort_by'].' '.$filter['sort_order'];
$res = $GLOBALS['db']->selectLimit($sql, $filter['page_size'], $filter['start']);
while ($rows = $GLOBALS['db']->fetchRow($res))
{
$rows['log_time'] = local_date($GLOBALS['_CFG']['time_format'], $rows['log_time']);
$list[] = $rows;
}
return array('list' => $list, 'filter' => $filter, 'page_count' => $filter['page_count'], 'record_count' => $filter['record_count']);
}


没有做任何过滤转义
但是管理员日志正常用户是没有办法直接控制的,我们就需要想办法间接去控制他
继续翻找代码 找关键字admin_log 找到有哪写代码会往日志数据库写数据的
找到user_msg.php文件有处 而这个是用来审核用户留言的 也就是说可控

elseif ($_REQUEST['act'] == 'remove')
{
$msg_id = intval($_REQUEST['id']);
/* 检查权限 */
check_authz_json('feedback_priv');
$msg_title = $exc->get_name($msg_id);
$img = $exc->get_name($msg_id, 'message_img');
if ($exc->drop($msg_id))
{
/* 删除图片 */
if (!empty($img))
{
@unlink(ROOT_PATH. DATA_DIR . '/feedbackimg/'.$img);
}
$sql = "DELETE FROM " . $ecs->table('feedback') . " WHERE parent_id = '$msg_id' LIMIT 1";
$db->query($sql, 'SILENT');
admin_log(addslashes($msg_title), 'remove', 'message');
$url = 'user_msg.php?act=query&' . str_replace('act=remove', '', $_SERVER['QUERY_STRING']);
ecs_header("Location: $url\n");
exit;
}
else
{
make_json_error($GLOBALS['db']->error());
}
}


发现这里直接把 $msg_title写进了admin_log

admin_log(addslashes($msg_title), 'remove', 'message');


$msg_title 是留言的标题 那在找留言出代码

$action  = isset($_REQUEST['act']) ? trim($_REQUEST['act']) : 'default';
if ($action == 'act_add_message')
{
include_once(ROOT_PATH . 'includes/lib_clips.php');
/* 验证码防止灌水刷屏 */
if ((intval($_CFG['captcha']) & CAPTCHA_MESSAGE) && gd_version() > 0)
{
include_once('includes/cls_captcha.php');
$validator = new captcha();
if (!$validator->check_word($_POST['captcha']))
{
show_message($_LANG['invalid_captcha']);
}
}
else
{
/* 没有验证码时,用时间来限制机器人发帖或恶意发评论 */
if (!isset($_SESSION['send_time']))
{
$_SESSION['send_time'] = 0;
}
$cur_time = gmtime();
if (($cur_time - $_SESSION['send_time']) < 30) // 小于30秒禁止发评论
{
show_message($_LANG['cmt_spam_warning']);
}
}
$user_name = '';
if (empty($_POST['anonymous']) && !empty($_SESSION['user_name']))
{
$user_name = $_SESSION['user_name'];
}
elseif (!empty($_POST['anonymous']) && !isset($_POST['user_name']))
{
$user_name = $_LANG['anonymous'];
}
elseif (empty($_POST['user_name']))
{
$user_name = $_LANG['anonymous'];
}
else
{
$user_name = htmlspecialchars(trim($_POST['user_name']));
}
$user_id = !empty($_SESSION['user_id']) ? $_SESSION['user_id'] : 0;
$message = array(
'user_id' => $user_id,
'user_name' => $user_name,
'user_email' => isset($_POST['user_email']) ? htmlspecialchars(trim($_POST['user_email'])) : '',
'msg_type' => isset($_POST['msg_type']) ? intval($_POST['msg_type']) : 0,
'msg_title' => isset($_POST['msg_title']) ? trim($_POST['msg_title']) : '',
'msg_content' => isset($_POST['msg_content']) ? trim($_POST['msg_content']) : '',
'order_id' => 0,
'msg_area' => 1,
'upload' => array()
);


也没有对代码进行过滤 msg_title也是直接写入

漏洞证明:

那直接试试

<script>alert(document.cookie)</script>


1.jpg


提交xss

2.jpg


成功
现在看后台

3.jpg


这里进行转义过滤 所以并没有形成xss
我们再删除这段留言后
进入日志查看

4.jpg


果然弹了

修复方案:

你们懂的

版权声明:转载请注明来源 路人甲@乌云


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-01-19 02:18

厂商回复:

最新状态:

暂无