记一次跨站脚本攻击审计过程

发布于 2017-01-09 17:26:56

前言

  前面的文章分享了一些Java中跨站脚本攻击的审计思路。结合github上某实际的代码环境进行相关的实战,以下记录相关的审计过程。

相关过程

  首先拿到工程代码后,先梳理前后端的处理以及渲染过程。这里可以通过类似关键字快速定位:

<%=
${

  通过关键字快速定位到一个切入点,该接口从用户输入获取occupationid以及questionxl两个参数的值,在存入request域后跳转到list2页面:

@RequestMapping(value="/edit") public String edit(HttpServletRequest request,String occupationid,String questionxl) throws Exception{ request.setAttribte("eq_occupationid",occupationid); request.setAttribte("eq_questionxl",questionxl); return "/query/analyse/list2" }

  追踪到list2页面查看,看看在对应的页面是否对刚刚存入request域的两个参数occupationid以及questionxl进行了展示,如果有的话,是否进行了输出编码处理。

class="mainContnt"> "分析结果查询" isShowTime="false" isShowJspName="flase"/>
"mainContent"> <%@ include file="/base-page/common/errormsg.jsp"%> "post" action="<%=webapp>/analyse/edit.act"> "eq_occupationid"/> "eq_questionxl"/>

  可以看到这里使用了jbfs标签进行了对应的展示,跟常见的JSTL、EL表达式有点不相同。在jsp开发时,当jsp内置标签以及JSTL标签库都满足不了需求时,可以根据自己的需求来自定义标签。这时候需要找相关的tld文件查看对应标签的具体实现方法。这里猜测是通过自定义一个标签库,满足一些常见的HTML标签以及对应属性的组装。
  一般tld文件都放在WEB-INF下,这样可以保证客户端访问不到。也可以在web.进行配置。
  查看web.相关配置,其使用 标签来引入自定义标签库,相关配置文件在tld目录下的tag.tld:

<jsp-config> <taglib> <taglib-uri>/WEB-INF/tld/tag.tldtaglib-uri> <taglib-location>/WEB-INF/tld/tag.tld taglib-location> taglib> <taglib> <taglib-uri>/WEB-INF/tld/sgrid.tldtaglib-uri> <taglib-location>/WEB-INF/tld/sgrid.tld taglib-location> taglib> <taglib> <taglib-uri>/WEB-INF/tld/greport.tldtaglib-uri> <taglib-location>/WEB-INF/tld/greport.tld taglib-location> taglib> jsp-config>

  查看tag.tld文件,刚刚我们在jsp页面看到引用方式是 ,搜索hidden关键字,相关内容如下:

<tag> <name>hiddenname> <tag-class> com.jbfs.base.tag.html.HiddenTag tag-class> <attribute> <name>idname> <required>falserequired> <rtexprvalue>truertexprvalue> <deion> 标签id

]]> deion> attribute> <attribute> <name>propertyname> <required>truerequired> <rtexprvalue>truertexprvalue> <deion> 标签的property属性

]]> deion> attribute> <attribute> <name>namename> <required>falserequired> <rtexprvalue>truertexprvalue> <deion> 标签name

]]> deion> attribute> <attribute> <name>valuename> <required>falserequired> <rtexprvalue>truertexprvalue> <deion> value属性

]]> deion> attribute> tag>

  也就是说该标签的定义方式主要在com.jbfs.base.tag.html包下的HiddenTag.java文件中。
  到com.jbfs.base.tag.html.HiddenTag类下查看具体实现:

package com.jbfs.base.tag.html; import javax.servlet.jsp.JspException; import com.jbfs.base.tag.AbstractTagSupport; /** * 该类是hidden标签 * @version 2013-06-06 * @author Leibf */ public class HiddenTag extends AbstractTagSupport { private static final long serialVersionUID = 1L; public HiddenTag() { super(); } public int doStartTag() throws JspException { StringBuffer content = new StringBuffer("< input "); this.prepareAttribute(content, "type", "hidden"); this.prepareAttribute(content, "value", this.preValue()); this.prepareAttributes(content); content.append("/>"); this.write(pageContext, content.toString()); return (EVAL_BODY_INCLUDE); } public int doEndTag() throws JspException { super.doEndTag(); this.release(); return EVAL_PAGE; } public void release() { super.release(); } }

  可以看到该类继承了AbstractTagSupport,然后通过prepareAttribute方法对标签进行封装。查看AbstractTagSupport.java中对于prepareAttribute方法的定义:

/**
 * 单个属性准备
 * 
 * @param content
 * @param name
 * @param value
 */
protected void prepareAttribute(StringBuffer content, String name, String value)
{
	if (value != null)
	{
		content.append(" ");
		content.append(name);
		content.append("=\"");
		content.append(this.evalString(name, value));
		content.append("\"");
	}
}

  到这里整个数据交互流程就出来了,也就是说,访问edit接口后,跳转到list2页面,从用户输入获取occupationid以及questionxl最后在页面中的呈现形式应该是这样的:

  这里可以看到,整个过程是没有相关的编码操作的,最简单的利用方式就是闭合双引号“,然后写入accesskey以及类似事件,通过组合快捷键触发。例如提交请求如下:

?occupationid="="comfirm(1)"accesskey="x&questionxl="="comfirm(1)"accesskey="x

  整理完相关的数据交互流程后,就是看一下是否有相关的安全防护措施了,这里使用了拦截器的方式进行相关的输入拦截,相关规则如下:

  可以看到拦截器的规则比较简单,并不能覆盖我们的标签中value属性的xss场景。到这里就成功得到了一个跨站脚本攻击的漏洞接口了。

具体修复

  修复的话主要是两个思路,一个是过滤敏感输入,这里其实已经有了,但是规则太简陋。例如一下JS事件、特殊符号,或者是编码绕过、JS全局变量等场景都需要考虑,其次就是输出编码。输出编码的话主要是要结合浏览器解析考虑特殊的编码场景,例如链接内容、内联的JavaScript代码块等。

8 条评论