Struts2(s2-016)远程代码执行漏洞详细代码分析
2013-07-25 19:02
1856 查看
之前 winwin 已经发过这个漏洞的分析文章,分析的很到位,不过有几个点有些问题,所以我在这里把自己的分析内容发出来,供各位参考。
这个漏洞的数据污染点和触发点,和其他的 Struts 不一样,所以本篇分析将从 Struts 执行流程中剖析此漏洞。在 Struts2.3 以后,官方将原有的起始过滤器换为:org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.class
所以我们此次跟踪的第一个断点便下在这个类的 doFilter 方法中,代码如下:
问题的关键点就在这个 result 属性中,Struts 在处理 action 后,返回的内容都是依赖 result 属性中的内容。平常这个属性都是通过配置文件来设置的,但是在这里,用户可以通过 redirect 来控制这个属性的内容。而且,用来解析返回内容的 conditionalParse 方法使用了 translateVariables 方法处理参数,这个方法会将其参数作为 Ognl 表达式执行,从而导致此漏洞的触发。conditionalParse 方法代码如下:
本文已经过重新排版。
转载自:http://www.2cto.com/Article/201307/230083.html
这个漏洞的数据污染点和触发点,和其他的 Struts 不一样,所以本篇分析将从 Struts 执行流程中剖析此漏洞。在 Struts2.3 以后,官方将原有的起始过滤器换为:org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.class
所以我们此次跟踪的第一个断点便下在这个类的 doFilter 方法中,代码如下:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; try { prepare.setEncodingAndLocale(request, response); prepare.createActionContext(request, response); prepare.assignDispatcherToThread(); if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { chain.doFilter(request, response); } else { request = prepare.wrapRequest(request); ActionMapping mapping = prepare.findActionMapping(request, response, true); if (mapping == null) { boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else { execute.executeAction(request, response, mapping); } } } finally { prepare.cleanupRequest(request); } }通过第 12 行获取当前访问的 action 映射,下面我们来看 PrepareOperations 类中的 findActionMapping 方法:
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) { ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY); if (mapping == null || forceLookup) { try { mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager()); if (mapping != null) { request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping); } } catch (Exception ex) { dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); } } return mapping; }跟进至第 5 行,这句代码通过调用 DefaultActionMapper 类的 getMapping 方法来获取 action 映射,我们继续跟进到这个方法:
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { ActionMapping mapping = new ActionMapping(); String uri = getUri(request); int indexOfSemicolon = uri.indexOf(";"); uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri; uri = dropExtension(uri, mapping); if (uri == null) { return null; } parseNameAndNamespace(uri, mapping, configManager); handleSpecialParameters(request, mapping); return parseActionName(mapping); }第 11 行代码用于处理特殊参数,本漏洞的触发点 redirect 就属于它处理的内容,下面我们来看下它的代码:
public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) { // handle special parameter prefixes. Set<String> uniqueParameters = new HashSet<String>(); Map parameterMap = request.getParameterMap(); for (Object o : parameterMap.keySet()) { String key = (String) o; // Strip off the image button location info, if found if (key.endsWith(".x") || key.endsWith(".y")) { key = key.substring(0, key.length() - 2); } // Ensure a parameter doesn't get processed twice if (!uniqueParameters.contains(key)) { ParameterAction parameterAction = (ParameterAction) prefixTrie.get(key); if (parameterAction != null) { parameterAction.execute(key, mapping); uniqueParameters.add(key); break; } } } }继续跟着流程走,第 15 行代码之前的操作是从用户传入的参数中提取特殊参数,第 15 行则是针对这个参数进行处理的地方。DefaultActionMapper 类针对四种不同的特殊参数,分别定义了不同的 execute 方法,这里我们只看处理 redirect 参数的方法,看下它的代码:
public void execute(String key, ActionMapping mapping) { ServletRedirectResult redirect = new ServletRedirectResult(); container.inject(redirect); redirect.setLocation(key.substring(REDIRECT_PREFIX.length())); mapping.setResult(redirect); }代码比较简单,就是新建一个 ServletRedirectResult 对象,将用户输入的参数值插入到它的 Location 属性中,最后将这个对象覆盖掉映射的 result 属性。
问题的关键点就在这个 result 属性中,Struts 在处理 action 后,返回的内容都是依赖 result 属性中的内容。平常这个属性都是通过配置文件来设置的,但是在这里,用户可以通过 redirect 来控制这个属性的内容。而且,用来解析返回内容的 conditionalParse 方法使用了 translateVariables 方法处理参数,这个方法会将其参数作为 Ognl 表达式执行,从而导致此漏洞的触发。conditionalParse 方法代码如下:
protected String conditionalParse(String param, ActionInvocation invocation) { if (parse && param != null && invocation != null) { return TextParseUtil.translateVariables(param, invocation.getStack(), new TextParseUtil.ParsedValueEvaluator() { public Object evaluate(String parsedValue) { if (encode) { if (parsedValue != null) { try { // use UTF-8 as this is the recommended encoding by W3C to // avoid incompatibilities. return URLEncoder.encode(parsedValue, "UTF-8"); } catch(UnsupportedEncodingException e) { if (LOG.isWarnEnabled()) { LOG.warn("error while trying to encode ["+parsedValue+"]", e); } } } } return parsedValue; } }); } else { return param; } }差不多就这些,应该够详细了。
本文已经过重新排版。
转载自:http://www.2cto.com/Article/201307/230083.html
相关文章推荐
- Struts2 S2 – 032远程代码执行漏洞分析报告
- Struts2 S2-016,S2-017远程代码执行漏洞解决,修复
- Struts2 S2 – 032远程代码执行漏洞分析报告 .
- S2-029 Struts2 标签远程代码执行分析(含POC)
- s2-029 Struts2 标签远程代码执行分析(含POC)
- struts2最新s2-016代码执行漏洞CVE-2013-2251
- CVE-2017-9805:Struts2 REST插件远程执行命令漏洞(S2-052) 分析报告
- Struts S2-016 远程任意命令执行漏洞检测代码
- Struts2远程命令执行漏洞 S2-045 源码分析
- CVE-2017-9805:Struts2 REST插件远程执行命令漏洞(S2-052) 分析报告
- CVE-2017-9805:Struts2 REST插件远程执行命令漏洞(S2-052) 分析报告
- CVE-2017-9805:Struts2 REST插件远程执行命令漏洞(S2-052) 分析报告
- Struts2 S2-029远程代码执行漏洞
- Struts2 远程执行代码(S2-016) 利用工具
- 漏洞--Struts2远程命令执行S2-016
- Struts2 REST 插件 XStream 远程代码执行漏洞 S2-052 复现过程
- CVE-2012-1876Microsoft Internet Explorer Col元素远程代码执行漏洞分析
- Struts2/XWork < 2.2.0远程执行任意代码漏洞分析及修补[转自Neeao's Blog]
- 技术文章 | CVE-2017-12615/CVE-2017-12616:Tomcat信息泄漏和远程代码执行漏洞分析报告
- 9.漏洞验证系列--Apache Struts2 远程命令执行(S2-045)