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
class1
2
3
4
5
6
7
8package 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
5doStartTag()
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
方法获得参数信息,该方法会直接调用HttpServletRequest
的getQueryString
的方法直接获取浏览器发送的请求信息。
之后又调用UrlHelper.parseQueryString(query)
以&
为分隔符将获取的请求信息分隔出不同的参数。将参数保存在queryParams
在该过程中会对参数的value值使用translateAndDecode
编码处理,而不会对参数name进行任何处理。
然后继续执行进入mergeRequestParameters
将参数名称和值保存到parameters
中。
至此doStartTag
工作完成,然后进入到doEndTag
方法
然后进入end
方法,实现对标签的内容渲染工作。
0x03 补丁分析
1 | //if the action was not explicitly set grab the params from the request |
补丁使用while
循环对<script>
进行去除,仍可使用<script boogle>
样式绕过。
payload1
"><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