内容简介:阅读本文需要具备的知识:影响漏洞版本:漏洞靶机代码: (下方通过该代码进行分析, 务必下载本地对比运行)
0x00 前言
阅读本文需要具备的知识:
- 熟悉J2EE开发, 主要是JSP开发
- 了解Struts2框架执行流程
0x01 漏洞复现
影响漏洞版本:
Struts 2.0.0 - Struts 2.0.11
漏洞靶机代码: (下方通过该代码进行分析, 务必下载本地对比运行)
https://github.com/dean2021/java_security_book/tree/master/Struts2/s2_002
测试POC:
http://localhost:8080/index.action?"><script>alert(1)</script><"
请求响应内容:
<body> <a href="//hello/hello_struts2.action?"><script>alert(1)</script><"=&%22%3E%3Cscript%3Ealert(1)%3C/script%3E%3C%22=">ä½ å¥½Struts2</a> </body>
0x02 漏洞分析
通过官网安全公告 参考[1],我们大概知道问题是出在
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <%@taglib prefix="s" uri="/struts-tags" %> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <body> <a href="<s:url action="/hello/hello_struts2" includeParams="all" ></s:url>">你好Struts2</a> </body> </html>
两个标签我们就分析
public abstract class ComponentTagSupport extends StrutsBodyTagSupport { public int doStartTag() throws JspException { // 实现子类是URL.class this.component = this.getBean(this.getStack(), (HttpServletRequest)this.pageContext.getRequest(), (HttpServletResponse)this.pageContext.getResponse()); Container container = Dispatcher.getInstance().getContainer(); container.inject(this.component); this.populateParams(); // 跟进URL类的start方法实现 boolean evalBody = this.component.start(this.pageContext.getOut()); if (evalBody) { return this.component.usesBody() ? 2 : 1; } else { return 0; } }
跟进URL类的start方法实现:
public class URL extends Component { public boolean start(Writer writer) { boolean result = super.start(writer); if (this.value != null) { this.value = this.findString(this.value); } try { // 我们在<s:url>这个标签内配置的includeParams="all" // 关于这个属性介绍,参考2 String includeParams = this.urlIncludeParams != null ? this.urlIncludeParams.toLowerCase() : "get"; if (this.includeParams != null) { includeParams = this.findString(this.includeParams); } if ("none".equalsIgnoreCase(includeParams)) { this.mergeRequestParameters(this.value, this.parameters, Collections.EMPTY_MAP); } else if ("all".equalsIgnoreCase(includeParams)) { // 我们跟进此方法的实现 this.mergeRequestParameters(this.value, this.parameters, this.req.getParameterMap()); this.includeGetParameters(); this.includeExtraParameters(); } else if (!"get".equalsIgnoreCase(includeParams) && (includeParams != null || this.value != null || this.action != null)) { if (includeParams != null) { LOG.warn("Unknown value for includeParams parameter to URL tag: " + includeParams); } } else { this.includeGetParameters(); this.includeExtraParameters(); } } catch (Exception var4) { LOG.warn("Unable to put request parameters (" + this.req.getQueryString() + ") into parameter map.", var4); } return result; }
this.mergeRequestParameters(this.value, this.parameters, this.req.getParameterMap()); 跟进实现:
protected void mergeRequestParameters(String value, Map parameters, Map contextParameters) { Map mergedParams = new LinkedHashMap(contextParameters); if (value != null && value.trim().length() > 0 && value.indexOf("?") > 0) { new LinkedHashMap(); String queryString = value.substring(value.indexOf("?") + 1); mergedParams = UrlHelper.parseQueryString(queryString); Iterator iterator = contextParameters.entrySet().iterator(); while(iterator.hasNext()) { Entry entry = (Entry)iterator.next(); Object key = entry.getKey(); if (!((Map)mergedParams).containsKey(key)) { ((Map)mergedParams).put(key, entry.getValue()); } } } Iterator iterator = ((Map)mergedParams).entrySet().iterator(); while(iterator.hasNext()) { Entry entry = (Entry)iterator.next(); Object key = entry.getKey(); if (!parameters.containsKey(key)) { parameters.put(key, entry.getValue()); } } }
从方法明明上我们已经能够看得出该方法是合并参数,通过阅读代码该方法的第三个参数也就是HttpServletRequest对象getParameterMap(), HttpServletRequest是Servlet原生对象,那这个方法具体是用来做什么的呢?下方是官方解释:
Returns a java.util.Map of the parameters of this request.
也就是返回一个map类型的request参数。我们请求的是url是:
http://localhost:8080/index.action?"><script>alert(1)</script><"
那么解析后的map就是 :
KEY = "><script>alert(1)</script><"
VAL = “”
然后进行参数合并, 并未看到对参数进行任何过滤,最后写入到html中,导致造成xss漏洞。
TIPS: 经过测试HttpServletRequest对象getParameterMap()方法只会对参数值进行转换编码,并不会对参数名进行任何处理.
0x03 总结:
Struts2框架的<s:url>标签的includeParams属性设置为all的情况下,对url参数名未做过滤,导致xss漏洞。
0x04 修复方案分析:
根据公告,我们需要升级到Struts 2.0.11.1版本。
经过对2.0.11.1的代码阅读,在UrlHelper类buildUrl方法里,第136行增加了如下修复代码:
// link是最终的生成的url for(result = link.toString(); result.indexOf("<script>") > 0; result = result.replaceAll("<script>", "script")) { }
看到这样的修复,虽然很无语,但是站在没有web安全知识的 程序员 角度来看待这种修复方案,能这样写也是很正常,因为大部分程序员只知道JavaScript代码是在 <script>
标签中执行。
好了,分析结束,附上一个bypass POC:
index.action?"><script 1>alert(1)</script>"
下一篇S2-003应该就是修复这个问题吧。
0x06 引用
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【FreeBuf字幕组】Web安全漏洞系列:Electron框架漏洞
- Play框架任意文件读取漏洞
- 漏洞预警丨某通用交易所框架组合型严重漏洞
- Web框架下安全漏洞的测试反思
- PHP框架Lavarel被发现存在高危漏洞
- ATtiny85漏洞利用框架HID测试分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ActionScript 3.0 Cookbook
Joey Lott、Darron Schall、Keith Peters / Adobe Dev Library / 2006-10-11 / GBP 28.50
Well before Ajax and Microsoft's Windows Presentation Foundation hit the scene, Macromedia offered the first method for building web pages with the responsiveness and functionality of desktop programs......一起来看看 《ActionScript 3.0 Cookbook》 这本书的介绍吧!