さくtwosmi1e

S2-002漏洞分析

twosmi1e·2020-12-14 17:40·730 次阅读

S2-002漏洞分析

漏洞概述#

Struts2-002是一个 XSS 漏洞,该漏洞发生在 <s:url><s:a>标签中,未对标签内字符进行转义,当标签的属性 includeParams=all 时,即可触发该漏洞。

漏洞影响版本: Struts 2.0.0 - Struts 2.1.8.1 。更多详情可参考官方通告:https://cwiki.apache.org/confluence/display/WW/S2-002

环境搭建#

直接在上一次S2-001的环境上做一些修改
index.jsp中,将上次的form表单删掉,添加一个<s:url>标签

Copy
<%-- Created by IntelliJ IDEA. User: twosmi1e Date: 2020/11/19 Time: 7:32 下午 To change this template use File | Settings | File Templates. --%> <%@ page language="java" contentType="text/html" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>S2-001</title> </head> <body> <h2>S2-001 Demo</h2> <p>link: <a href="https://cwiki.apache.org/confluence/display/WW/S2-001">https://cwiki.apache.org/confluence/display/WW/S2-001</a></p> <s:url action="login" includeParams="all"></s:url> </body> </html>

LoginAction.java中添加url变量,将对用户名密码的处理删掉

Copy
package com.demo.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private String username = null; private String password = null; private String url = null; public String getUsername() { return this.username; } public String getPassword() { return this.password; } public String getUrl(){ return this.url; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public void setUrl(String url){ this.url = url; } public String execute() throws Exception { return "error"; } }

运行复现漏洞

成功触发XSS

漏洞分析#

当在 JSP 文件中遇到 Struts2 标签 <s: 时,程序会先调用 doStartTag ,并将标签中的属性设置到对应标签对象相应属性中。最后,在遇到 /> 结束标签的时候调用 doEndTag 方法。

跟进component.start函数

可以看到函数会根据标签includeParams属性不同做不同处理
all 和 get 的不同只有一个 mergeRequestParameters 方法,在 includeParams 为 all 的情况下会调用 mergeRequestParameters 将 tomcat 处取来的参数:

这里取到了我们输入的payload,并且保存在parameters

在 mergeRequestParameters 方法之后,依次是 includeGetParameters、includeExtraParameters 方法。 includeGetParameters 方法主要是将 HttpRequest.getQueryString() 的数据存入 this.parameters 属性,而 includeExtraParameters 方法则用来存入其它数据。

而在 get 时会调用的两个函数中,includeGetParameters 方法则是先获取请求参数字符串,再进行处理分割:

而调用 this.req.getQueryString 从 tomcat 处获取的请求参数字符串是经过 URL 编码的,所以无法造成 XSS 漏洞。

includeExtraParameters 则一般为 null。

执行完doStartTag后进入doEndTag,调用buildUrl

然后返回result触发XSS

漏洞修复#

2.0.11.1 版本修复#

对 s:a 标签的修复如下:

Copy
if (this.href != null) { this.addParameter("href", this.ensureAttributeSafelyNotEscaped(this.findString(this.href))); }

加上了一个 ensureAttributeSafelyNotEscaped 方法来过滤双引号:

Copy
protected String ensureAttributeSafelyNotEscaped(String val) { return val != null ? val.replaceAll("\"", "&#34;") : ""; }

对 s:url 标签的修复如下:

Copy
for(result = link.toString(); result.indexOf("<script>") > 0; result = result.replaceAll("<script>", "script")) { ; }

在拼接完之后对 script 进行了处理,但是只是简单的将 script 标签的两个尖括号去掉了,所以可以轻松绕过:

http://localhost:8080/login.action?<script 1>alert(1)</script>=hello

2.2.1 版本修复#

Copy
private static String buildParameterSubstring(String name, String value) { StringBuilder builder = new StringBuilder(); builder.append(translateAndEncode(name)); builder.append('='); builder.append(translateAndEncode(value)); return builder.toString(); } public static String translateAndEncode(String input) { String translatedInput = translateVariable(input); String encoding = getEncodingFromConfiguration(); try { return URLEncoder.encode(translatedInput, encoding); } catch (UnsupportedEncodingException e) { LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded"); return translatedInput; } }

使用url编码修复了漏洞

参考#

https://aluvion.gitee.io/2020/07/15/struts2系列漏洞-S2-002/
https://mochazz.github.io/2020/06/17/Java代码审计之Struts2-002/

posted @   twosmi1e  阅读(730)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示
目录