披露状态:
2014-12-13: 细节已通知厂商并且等待厂商处理中
2014-12-18: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2015-02-11: 细节向核心白帽子及相关领域专家公开
2015-02-21: 细节向普通白帽子公开
2015-03-03: 细节向实习白帽子公开
2015-01-19: 细节向公众公开
简要描述:
N久了,你们是修还是不修啊?这么蛋疼的一个漏洞.
详细说明:
先看admin_logs.php代码
code 区域
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文件有处 而这个是用来审核用户留言的 也就是说可控
code 区域
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
code 区域
admin_log(addslashes($msg_title), 'remove', 'message');
$msg_title 是留言的标题 那在找留言出代码
code 区域
$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也是直接写入
漏洞证明:
那直接试试
code 区域
<script>alert(document.cookie)</script>
提交xss
成功
现在看后台
这里进行转义过滤 所以并没有形成xss
我们再删除这段留言后
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论