JEECMS XssFilter缺陷导致的存储型XSS漏洞

admin 2017年4月28日02:37:52评论453 views字数 221阅读0分44秒阅读模式
摘要

2016-03-07: 细节已通知厂商并且等待厂商处理中
2016-03-08: 厂商已经确认,细节仅向厂商公开
2016-03-11: 细节向第三方安全合作伙伴开放(绿盟科技、唐朝安全巡航、无声信息)
2016-05-02: 细节向核心白帽子及相关领域专家公开
2016-05-12: 细节向普通白帽子公开
2016-05-22: 细节向实习白帽子公开
2016-06-06: 细节向公众公开

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

缺陷编号: WooYun-2016-181732

漏洞标题: JEECMS XssFilter缺陷导致的存储型XSS漏洞 JEECMS XssFilter缺陷导致的存储型XSS漏洞

相关厂商: JEECMS

漏洞作者: applychenJEECMS XssFilter缺陷导致的存储型XSS漏洞

提交时间: 2016-03-07 09:00

公开时间: 2016-06-06 14:20

漏洞类型: 设计缺陷/逻辑错误

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

漏洞来源:www.wooyun.org ,如有疑问或需要帮助请联系

Tags标签: 无

6人收藏


漏洞详情

披露状态:

2016-03-07: 细节已通知厂商并且等待厂商处理中
2016-03-08: 厂商已经确认,细节仅向厂商公开
2016-03-11: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2016-05-02: 细节向核心白帽子及相关领域专家公开
2016-05-12: 细节向普通白帽子公开
2016-05-22: 细节向实习白帽子公开
2016-06-06: 细节向公众公开

简要描述:

自带的XssFilter绕过。

详细说明:

在官网下载最新的jeecmsV7

code 区域
http://**.**.**.**/fabu/41667.jhtml

其中的web.xml中配置了XssFilter如下:

code 区域
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>**.**.**.**mon.web.XssFilter</filter-class>
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value>
</init-param>
<init-param>
<param-name>SplitChar</param-name>
<param-value>@</param-value>
</init-param>
<init-param>
<param-name>FilterChar</param-name>
<param-value>'@"@/@#@:@%@></param-value>
</init-param>
<init-param>
<param-name>ReplaceChar</param-name>
<param-value>@\@#@:@%@></param-value>
</init-param>
</filter>

在**.**.**.**mon.web.XssFilter中代码如下:

code 区域
public class XssFilter implements Filter {
private String filterChar;
private String replaceChar;
private String splitChar;
private String excludeUrls;
FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterChar=filterConfig.getInitParameter("FilterChar");
this.replaceChar=filterConfig.getInitParameter("ReplaceChar");
this.splitChar=filterConfig.getInitParameter("SplitChar");
this.excludeUrls=filterConfig.getInitParameter("excludeUrls");
this.filterConfig = filterConfig;
}

public void destroy() {
this.filterConfig = null;
}

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException {
if(isExcludeUrl(request)){
chain.doFilter(request, response);
}else{
chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request,filterChar,replaceChar,splitChar), response);
}
}


private boolean isExcludeUrl(ServletRequest request){
boolean exclude=false;
if(StringUtils.isNotBlank(excludeUrls)){
String[]excludeUrl=excludeUrls.split(splitChar);
if(excludeUrl!=null&&excludeUrl.length>0){
for(String url:excludeUrl){
if(URLHelper.getURI((HttpServletRequest)request).startsWith(url)){
exclude=true;
}
}
}
}
return exclude;
}

}

注意其中的isExcludeUrl(ServletRequest request)方法,isExcludeUrl()用于排除web.xml中定义的URL(即白名单,XssFilter不检查web.xml定义页面中的XSS字符)如下():

code 区域
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value>
</init-param>

在具体实现xss白名单的的时候使用的是startsWith():

code 区域
if(URLHelper.getURI((HttpServletRequest)request).startsWith(url)){
exclude=true;
}

即URI目录以以下字符开头即可绕过XssFilter的检查:

code 区域
/member/contribute
/jeeadmin/jeecms
/flow_statistic

再来看

RequestUtils.java中的getIpAddr(HttpServletRequest request)方法:

code 区域
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
ip = request.getHeader("X-Forwarded-For");
if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个IP值,第一个为真实IP。
int index = ip.indexOf(',');
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
} else {
return request.getRemoteAddr();
}
}

此方法用于获取ip地址,可以从以下两个HTTP头中获取:

code 区域
X-Real-IP
X-Forwarded-For

getIpAddr(HttpServletRequest request)在CommentAct.java中被调用:

code 区域
@RequestMapping(value = "/comment.jspx", method = RequestMethod.POST)
public void submit(Integer contentId, Integer score,String text, String captcha,
HttpServletRequest request, HttpServletResponse response,
ModelMap model) throws JSONException {
……
cmsCommentM**.**.**.**ment(score,text, RequestUtils.getIpAddr(request),
contentId, site.getId(), userId, checked, false);
json.put("success", true);
json.put("status", 0);
}
ResponseUtils.renderJson(response, json.toString());
}

通过cmsCommentM**.**.**.**ment()直接把IP地址RequestUtils.getIpAddr(request)写入到数据库,首先是正常的在前台文章进行评论,抓包写入HTTP头:

JEECMS XssFilter缺陷导致的存储型XSS漏洞

在后台查看可以看到>符号被替换为>:

JEECMS XssFilter缺陷导致的存储型XSS漏洞

下面来开始绕过,前台评论:

JEECMS XssFilter缺陷导致的存储型XSS漏洞

抓包拦截,将URL修改为以/jeeadmin/jeecms/开头:

code 区域
/jeeadmin/jeecms/../../comment.jspx

添加获取IP的HTTP头:

code 区域
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>**.**.**.**mon.web.XssFilter</filter-class>
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value>
</init-param>
<init-param>
<param-name>SplitChar</param-name>
<param-value>@</param-value>
</init-param>
<init-param>
<param-name>FilterChar</param-name>
<param-value>'@"@/@#@:@%@></param-value>
</init-param>
<init-param>
<param-name>ReplaceChar</param-name>
<param-value>@\@#@:@%@></param-value>
</init-param>
</filter>

0

整个包如下:

code 区域
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>**.**.**.**mon.web.XssFilter</filter-class>
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value>
</init-param>
<init-param>
<param-name>SplitChar</param-name>
<param-value>@</param-value>
</init-param>
<init-param>
<param-name>FilterChar</param-name>
<param-value>'@"@/@#@:@%@></param-value>
</init-param>
<init-param>
<param-name>ReplaceChar</param-name>
<param-value>@\@#@:@%@></param-value>
</init-param>
</filter>

1

当管理员在后台审核评论时即可触发跨站,如下图:

JEECMS XssFilter缺陷导致的存储型XSS漏洞

RequestUtils.getIpAddr(request)还在登录时被调用了,前台登录:

code 区域
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>**.**.**.**mon.web.XssFilter</filter-class>
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value>
</init-param>
<init-param>
<param-name>SplitChar</param-name>
<param-value>@</param-value>
</init-param>
<init-param>
<param-name>FilterChar</param-name>
<param-value>'@"@/@#@:@%@></param-value>
</init-param>
<init-param>
<param-name>ReplaceChar</param-name>
<param-value>@\@#@:@%@></param-value>
</init-param>
</filter>

2

登录成功后,管理员在后台点击用户模块即可触发跨站:

JEECMS XssFilter缺陷导致的存储型XSS漏洞

RequestUtils.getIpAddr(request),后台登录调用:

code 区域
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>**.**.**.**mon.web.XssFilter</filter-class>
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value>
</init-param>
<init-param>
<param-name>SplitChar</param-name>
<param-value>@</param-value>
</init-param>
<init-param>
<param-name>FilterChar</param-name>
<param-value>'@"@/@#@:@%@></param-value>
</init-param>
<init-param>
<param-name>ReplaceChar</param-name>
<param-value>@\@#@:@%@></param-value>
</init-param>
</filter>

3

管理员在后台查看登录失败日志即可触发跨站:

JEECMS XssFilter缺陷导致的存储型XSS漏洞

漏洞证明:

同上

修复方案:

1. 在获取URLHelper.getURI((HttpServletRequest)request)时候检查其中是否有../字符

2. 在旧版本中检查了IP地址的合法性,但是新版的v7反而没有了,可以添加上。

版权声明:转载请注明来源 applychen@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2016-03-08 14:17

厂商回复:

感谢对JEECMS的关注与支持,漏洞会尽早修复

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(少于3人评价):

登陆后才能进行评分

100%

0%

0%

0%

0%


评价

  1. 2016-03-07 09:32 | 爱上襄阳 ( 普通白帽子 | Rank:351 漏洞数:88 | ...)

    2

    applychen,我偶像!

  2. 2016-03-08 09:52 | Wens0n ( 普通白帽子 | Rank:102 漏洞数:23 | 精华漏洞数:32 | WooYun认证√ 舞蹈系教授)

    2

    @applychen 是不是要把开源程序都审计一篇,哈哈

  3. 2016-03-14 23:54 | ramos ( 路人 | Rank:7 漏洞数:1 | hello)

    2

    我猜是jeecms在web的xml配置的xssfilter对flow_statistic.jspx文件f放行,导致对page和reffer参数放行,管理员后台点击来源页面触发xss,楼主我们说的是不是同一个

  4. 2016-03-15 01:03 | applychen JEECMS XssFilter缺陷导致的存储型XSS漏洞 ( 普通白帽子 | Rank:667 漏洞数:57 | 万古漫漫长如夜)

    1

    @ramos 有点擦边

  5. 2016-03-15 09:44 | LoveSnow ( 实习白帽子 | Rank:85 漏洞数:20 | 以正和,以奇胜!)

    1

    @applychen能不能给我留个cms,我正在代码审计,结果你就给报了,唉。。

  6. 2016-06-25 19:48 | ramos ( 路人 | Rank:7 漏洞数:1 | hello)

    0

    @applychen 呵呵,我也看到过这块,不过我用浏览器访问../的网站,浏览器直接忽略了,应该抓包改包的,错过了一个大漏洞

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin