S2-029 远程代码执行漏洞检测与利用

本文深入分析Struts2029漏洞,探讨其在不同版本中的表现及修复情况。通过源码跟踪,揭示漏洞根源及双重执行机制。

概述

struts2 029漏洞已经爆出一段时间,网上有一些相关分析,首先,漏洞确定是出现在OGNL解释执行的过程,具体漏洞测试poc网上已经有很多,我在2.2.1、2.3.24.1、2.3.25、2.5beta3、2.3.26上面测试都可以执行,不过修改的安全参数稍微不同。

2.2.1只需要下面几个:

#_memberAccess['allowPrivateAccess']=true

#_memberAccess['allowProtectedAccess']=true

#_memberAccess['allowPackageProtectedAccess']=true

#_memberAccess['allowStaticMethodAccess']=true

2.3.24.1和2.5beta3则需要:

#_memberAccess['allowPrivateAccess']=true

#_memberAccess['allowProtectedAccess']=true

#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties']

#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties']

#_memberAccess['allowPackageProtectedAccess']=true

#_memberAccess['allowStaticMethodAccess']=true

2.3.25和2.3.26 则需要

#_memberAccess['excludedPackageNames']=#_memberAccess['acceptProperties']

#_memberAccess['allowPrivateAccess']=true

#_memberAccess['allowProtectedAccess']=true

#_memberAccess['excludedPackageNamePatterns']=#_memberAccess['acceptProperties']

#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties']

#_memberAccess['allowPackageProtectedAccess']=true

#_memberAccess['allowStaticMethodAccess']=true

话说官方说的升级到2.3.25就没事了是咋回事?

分析

下面就对2.3.25进行跟踪分析一下。

首先官网还没有2.3.25的编译版本下载,有的只是beta版。而beta版的代码经过对比,发现还是有很多与2.3.25不同的,故github 2.3.25源码,然后mvn install -Dmaven.test.skip=true编译。

编译好之后,部署测试程序。Poc测试代码如下:

这里先说明一下,漏洞的根源是调用findString、findValue等函数。所以切换到
/struts-STRUTS_2_3_25/core/src/main/java/org/apache/struts2/components下面,对这里的源码进行查找findValue参数,可以发现很多类都有调用

下面我们对textfield这个标签举例进行跟踪分析。Textfield有很多属性,

我们先看下size属性,通过findString查找size,findString的定义如下:

可以看到它实际调用findValue(expr,String.class),定义如下:

而这个函数判断传入的如果是String类的话,会调用TextParseUtil.translateVariables,先解析字符串后在去执行expr,否则直接执行expr。getStack().findValue()就是代码被解释执行的位置,这时候的expr的%{}会被去掉。

这里注意到一个问题,就是相对2.3.25之前的版本,此处多了一个ComponentUtils.containsExpression(expr)判断,该函数是检测expr表达式中是否同时包含”%{“和”}”,如果是,返回真。也就是检测传入的字符串是不是标准的OGNL表达式。这个判断可能会有点用。比如,如果我们想通过size参数带入执行代码,如果我们直接写size=”expr”,那么expr进入findValue(expr,String.class)后过不了ComponentUtils.containsExpression(expr)的判断,什么都不执行直接返回。想要执行,必须写成%{expr}。其他用途还没看出来。

下面还要说下readonly属性,这个属性是布尔型,而findValue(expr,String.class)中如果不是String类型的话,不需要%{}就可以直接执行,也就是说readonly=”expr”就会被执行。

上面说的是OGNL代码的正常执行过程,代码只被执行一次。而这次漏洞报的是双重执行,也就是expr在一次请求中存在被解释执行两次的情况。这个情况在i18n源码中存在,具体细节请参考http://www.freebuf.com/vuls/99432.html。通过图2,可以发现在UIBean中也存在这样的情况。进一步查找,可以发现可疑情况:

其中UIBean中有三处出现对name属性进行执行的操作,查看代码逻辑发现果然有问题:

其中就有TextField。而UIBean的属性也不少。其中的name和value值得关注。

先是

得到name的string,之后到这里

会先尝试获取value的值,如果value为空,那么就二次解释执行了name。并且在执行前给name加上了”%{}”。最终造成二次执行。

而UIBean被很多类继承:

类似的textarea、label、hidden等都存在二次执行问题。

另外在2.3.25中多了#_memberAccess['excludedPackageNames']

所以必须将其清空,我们的payload才能执行。

结论

该漏洞可利用性比较困难,能够双重执行的属性位于name中,而我们通常可以传参的地方是value(不排除哪个程序员可以让你操控name属性值,同时你的value值还为空的情况),查找value的执行情况:

出现在Param.java和UIBean.java中,而阅读代码后,发现这两次执行都是位于不同分支中,不能造成二次执行的情况。

所以此次漏洞危害不算大,不过就是官方说的修复有点不理解。最后给出我测试的2.3.25和2.3.26的完整war包,测试uri:http://localhost:8080/2.3.25/http://localhost:8080/2.3.26/

执行的命令是touch /tmp/fuckp4e。部署并访问uri后,如果出现此文件,说明存在漏洞。

### Struts2 S2-061 远程代码执行漏洞分析 Apache Struts2 是一个广泛使用的 Java Web 开发框架,其设计基于 MVC 架构,提供了强大的标签库和 OGNL 表达式解析功能。然而,在 2020 年 12 月 8 日,Apache Struts 官方披露了 S2-061 远程代码执行漏洞(CVE-2020-17530),该漏洞源于某些标签属性在特定情况下会进行 OGNL 表达式的二次解析,从而导致 OGNL 注入漏洞。攻击者可以构造恶意请求,远程执行任意命令,甚至控制服务器,造成严重安全风险 [^1]。 漏洞的核心在于 Struts2 对某些标签属性(如 `id`)的值进行两次 OGNL 表达式解析。当这些属性值中包含 `%{x}` 形式的内容,且 `x` 的值由用户控制时,攻击者可以注入恶意的 OGNL 表达式,例如 `%{payload}`,从而触发远程代码执行 [^3]。 S2-061 是对之前 S2-059 漏洞的修复绕过。S2-059 的补丁主要修复了沙盒绕过问题,但未完全阻止 OGNL 表达式的执行。S2-061 利用了 `org.apache.commons.collections.BeanMap` 类,该类存在于 `commons-collections-x.x.jar` 包中,而 Struts2 官方最小依赖包并未包含此库。因此,即使存在支持 OGNL 表达式注入的点,若未使用该依赖包,也无法成功利用 [^3]。 ### 漏洞影响范围 S2-061 漏洞影响使用 Apache Struts2 的多个版本,尤其是在使用某些标签属性时存在 OGNL 表达式二次解析的情况。攻击者可以构造特定的请求,利用该漏洞远程执行任意命令,进而控制服务器,造成数据泄露、系统瘫痪等严重后果 [^1]。 ### 修复方案 1. **升级 Struts2 版本**:官方在漏洞披露后发布了修复版本,建议用户尽快升级到 Struts 2.5.26 或更高版本。新版本中对 OGNL 表达式的解析机制进行了改进,避免了标签属性的二次解析问题 [^1]。 2. **避免使用用户输入构造 OGNL 表达式**:在开发过程中,应避免将用户输入直接拼接到 OGNL 表达式中,尤其是标签属性值。应使用安全的输入验证和输出编码机制,防止恶意输入被当作表达式解析 [^3]。 3. **移除不必要的依赖库**:由于 S2-061 的利用依赖于 `commons-collections` 包,因此建议检查项目依赖,移除不必要的 `commons-collections` 版本,以降低攻击面 [^3]。 4. **启用安全模式(沙盒)**:Struts2 提供了安全模式(沙盒)功能,可以在一定程度上限制 OGNL 表达式的执行。建议在配置文件中启用沙盒模式,并限制表达式的执行权限 [^4]。 5. **部署 Web 应用防火墙(WAF)**:为了进一步增强安全性,建议在前端部署 Web 应用防火墙(WAF),对请求进行过滤和检测,识别并拦截包含 OGNL 表达式的恶意请求 [^2]。 ### 示例代码:安全的输入处理 以下是一个简单的示例,展示如何避免将用户输入直接拼接到 OGNL 表达式中: ```java public class SafeInputAction { private String userInput; public String execute() { // 对用户输入进行过滤和转义 String safeInput = escapeUserInput(userInput); // 将安全处理后的输入用于业务逻辑 // ... return "success"; } private String escapeUserInput(String input) { // 实现输入过滤逻辑,如移除特殊字符 if (input == null) { return null; } return input.replaceAll("[^a-zA-Z0-9]", ""); } // Getter 和 Setter public String getUserInput() { return userInput; } public void setUserInput(String userInput) { this.userInput = userInput; } } ``` 在 JSP 页面中,确保标签属性不直接使用用户输入构造 OGNL 表达式: ```jsp <s:textfield name="userInput" label="请输入内容" /> ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值