java代码审计入门之s2-002复现分析

0x00 前言

入门JAVA代码审计的第二篇文章,复现分析S2-002 xss漏洞。

本篇在漏洞分析的基础上,重点追踪了struts2标签解析过程。

0x01 环境搭建

官方公告中给出的漏洞影响版本为Struts 2.0.0 - Struts 2.0.11,因此本环境可以在之前分析s1-001漏洞环境上搭建,可参考前面的文章java代码审计入门之s2-001复现分析

在上面环境的基础上,继续创建xss_test.jsp

1
2
3
4
5
6
7
8
9
10
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>S2-002</title>
</head>
<body>
<a href="<s:url action="Xss" includeParams="all" ></s:url>">你好Struts2</a>
</body>
</html>

创建Xss.java class

1
2
3
4
5
6
7
8
package com.demo.action;
import com.opensymphony.xwork2.ActionSupport;
public class Xss extends ActionSupport{
public String execute() throws Exception {

return SUCCESS;
}
}

struct.xml中添加

1
2
3
<action name="Xss" class="com.demo.action.Xss">
<result name="success">xss_test.jsp</result>
</action>

0x02 代码分析

首先看一下官方关于漏洞的描述

可以看到漏洞主要原因是Struts 2框架在处理<s:url><s:a>标签时,未对标签内的字符进行转义,导致XSS漏洞。
在我们搭建的Demo中,以<s:url>标签为例进行分析
这里需要说明的是struts2允许使用自定义的其自定义的标签,如上面的<s:url>即为struct2 url标签。在使用struts2标签时需在页面中添加<%@ taglib uri ="/struts-tags" prefix ="s" %>。引入标签配置。该配置在struts2-core核心jar包中,META-INF/struts-tags.tld对struts2标签进行了定义。
比如我们本次使用的<s:url>

<tag-class>org.apache.struts2.views.jsp.URLTag</tag-class>说明了标签的具体实现类为org.apache.struts2.views.jsp.URLTag

在本例中<s:url>标签在xss_test.jps中,jsp的本质也是一个Servlet,在执行jsp的时候tomcat会将其转化为java代码,当struts2在解析到标签时,实际上是继承了http servlet中可扩展的BodyTagSupport类。
然后依次执行

1
2
3
4
5
doStartTag()
setBodyContent()
doInitBody()
doAfterBody()
doEndTag()

我们从doStartTag方法下断开始跟踪。
使用payload访问localhost:8080/test_war_exploded/Xss.action?"><script>alert(1)</script>=boogle

doStartTag方法中通过gettBean()方法获取URL组件,然后通过populateParams()方法对获取的URL组件中属性进行赋值。
然后执行this.component.start(this.pageContext.getOut())方法,即前面提到的URL组件的start方法。
跟进该方法

首先会判断<s:url>标签中设置的includeParams参数,该属性有三个值:none get all,默认值为get。属性值为get时,该url会将访问其所在jsp的的请求的所有get方法的参数添加到自身来 ,属性值为all时更是将get和post的的参数值全部添加到自身来,属性值为none时不添加。
本例中我们设置的参数值为all,之后便进入到includeParams值为all的流程,执行mergeRequestParameters方法。
跟进

在该方法中取到我们的payload,并保存在parameters中。
然后回到URL组件的start方法中,继续执行进入到includeGetParameters方法。

该方法中使用extractQueryString方法获得参数信息,该方法会直接调用HttpServletRequestgetQueryString的方法直接获取浏览器发送的请求信息。
之后又调用UrlHelper.parseQueryString(query)&为分隔符将获取的请求信息分隔出不同的参数。将参数保存在queryParams

在该过程中会对参数的value值使用translateAndDecode编码处理,而不会对参数name进行任何处理。
然后继续执行进入mergeRequestParameters将参数名称和值保存到parameters中。
至此doStartTag工作完成,然后进入到doEndTag方法

然后进入end方法,实现对标签的内容渲染工作。

0x03 补丁分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//if the action was not explicitly set grab the params from the request
if (escapeAmp) {
buildParametersString(params, link);
} else {
buildParametersString(params, link, "&");
}
String result = link.toString();
while (result.indexOf("<script>") > 0) {
result = result.replaceAll("<script>", "script");
}
try {
result = encodeResult ? response.encodeURL(result) : result;
} catch (Exception ex) {
// Could not encode the URL for some reason
// Use it unchanged
result = link.toString();
}

补丁使用while循环对<script>进行去除,仍可使用<script boogle>样式绕过。
payload

1
"><script boogle>alert(1)</script>=boogle

0x04 参考

Struts2标签原理分析
https://www.iflym.com/index.php/code/resolve-error-codec-problem-while-use-s-url-or-s-a-on-struts2.html

本文标题:java代码审计入门之s2-002复现分析

文章作者:boogle

发布时间:2019年04月17日 - 12:25

最后更新:2019年04月17日 - 16:30

原始链接:https://zhengbao.wang/java代码审计入门之s2-002复现分析/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

感觉写的不错,给买个棒棒糖呗