Struts2-002 漏洞分析

漏洞概要

可参考官方安全公告:https://cwiki.apache.org/confluence/display/WW/S2-002

漏洞分析

通过官网的安全公告,我们大概知道问题是出在标签<s:url><s:a>标签

中,如下是我们的index.jsp代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>s2-002</title>
</head>
<body>
<h2>s2-002 demo</h2>
<p>link: <a href="https://cwiki.apache.org/confluence/dispaly/WW/S2-002">
</a>https://cwiki.apache.org/confluence/dispaly/WW/S2-002 </p>
<s:url action="login" includeParams="all" ></s:url>
</body>
</html>

由于s2的标签库都是集成与ComponentTagSupport类,doStartTag方法也是在该类里实现,所以我们直接从ComponentTagSupportdoStartTag方法进行断点调试, 首先我们看一下doStartTag方法:

image-20201220160944540

image-20201220161002678

由于我们这里处理的是 s:url 标签,所以这里用来处理标签的组件 this.componentorg.apache.struts2.components.URL类对象。我们跟进 URL:start()方法。

image-20201221141410686

URL:start()方法中,我们看到当includeParams=all时,会调用 mergeRequestParameters方法。

image-20201221141714877

mergeRequestParameters方法中,程序会将 this.req.getParameterMap()获得的键值对数据存入 this.parameters属性。

getParameterMap()返回一个map类型的request参数

1
http://192.168.174.1:8888/Struts2_demo_war_exploded/?<script>alert(1)</script>

那么解析后的map就是 : key= <script>alert(1)</script>、vaule = "" 并未看到对参数进行任何过滤,

getParameterMap()方法并不会对数据进行任何处理。可见下文demo实例

image-20201221142411460

image-20201221142719076

image-20201221142946058

最后进入doEndTag方法进行处理

image-20201221170346052

image-20201221170317717

determineActionURL方法中调用了URLHelper类处理 this.parameters 数据并进行返回

image-20201221153821932

image-20201221153301168

将其写入,导致XSS漏洞。

image-20201221153500644

image-20201222113854119

includeParams=get时并不能触发 XSS 漏洞。

主要原因在于:当includeParams=all时,会多执行一个mergeRequestParameters 方法,而该方法会将 this.req.getParameterMap()数据设置到this.parameters 。如果 includeParams=get,那么 this.parameters中的数据,仅是来自 this.req.getQueryString()

image-20201222113001419

image-20201222113440372

this.req.getParameterMap()获得的数据会主动进行URLdecode ,但是this.req.getQueryString()不会。所以 includeParams=get时,返回的数据是被 URLencode 过的,因此不能触发 XSS 漏洞。可见下文demo实例

demo实例

demo实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.test;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

@WebServlet("/test")
public class Hello extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("getQueryString:"+"\n"+request.getQueryString());
Map<String, String[]> parameterMap = request.getParameterMap();
Iterator<Map.Entry<String, String[]>> iterator = parameterMap.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, String[]> next = iterator.next();
System.out.println("getParameterMap:"+"\n"+"key="+next.getKey()+'\n'+"value="+next.getValue()[0]);
}
}
}

image-20201221180716399

Poc:

1
?<script>alert(1)</script>

修复

根据公告,我们需要升级到Struts 2.0.11.1版本,未真正修复,仅仅是对script标签进行替换,仍然可以对其进行绕过

image-20201222111554160

bypass POC:

1
2
3
?<script 1>alert(1)</script>
?<strong>script</strong>
...

参考

https://cwiki.apache.org/confluence/display/WW/S2-002

https://xz.aliyun.com/t/7916

https://dean2021.github.io/posts/s2-002/

-本文结束感谢您的阅读-