Struts2远程代码执行漏洞(S2-037)技术分析与防护方案

继Apache Struts S2-033后,Apache官方披露了一个新的高级别漏洞,影响范围比S2-033更广。无论是否在开启动态方法调用(Dynamic Method Invocation)的情况下,攻击者使用REST插件调用恶意表达式均可以远程执行代码。
此漏洞编号为 CVE-2016-4438,定名为 S2-037。

官方公告地址:https://cwiki.apache.org/confluence/display/WW/S2-037

影响的版本

  • Apache Struts 2.3.20 – 2.3.28.1,=2.5。

不受影响的版本

  • Apache Struts 2.3.29,2.5.1。

漏洞分析

通过对代码库的对比发现修复方法如下:

代码库的对比

分析发现,修复的地方为在启用了动态方法调用(Dynamic Method Invocation)的情况下,通过cleanupActionName函数对OGNL表达式过滤,阻止恶意OGNL表达式执行。

查看Apache Structs 2.3.28.1的源文件RestActionMapper.java,发现修复的地方在函数handleDynamicMethodInvocation中,代码分析如下:

void handleDynamicMethodInvocation(ActionMapping mapping, String name) {
    int exclamation = name.lastIndexOf("!");
    if (exclamation != -1) {
        String actionName = name.substring(0, exclamation);
        String actionMethod = name.substring(exclamation + 1);

        // WW-4585
        // add any ; appendix to name, it will be handled later in getMapping method
        int scPos = actionMethod.indexOf(';');
        if (scPos != -1) {
            actionName = actionName + actionMethod.substring(scPos);
            actionMethod = actionMethod.substring(0, scPos);
        }
        mapping.setName(actionName);        
         //这里对actionName通过cleanupActionName过滤,也是可以阻止嵌入到name中的恶意OGNL表达式执行。
        if (allowDynamicMethodCalls) {
            mapping.setMethod(actionMethod);  
         //2.3.29目前修复此处为mapping.setMethod(cleanupActionName(actionMethod));
        //启用动态方法调用,则setMethod为actionMethod
        //没有加入cleanupActionName过滤函数,导致执行恶意OGNL表达式。
        } else {
            mapping.setMethod(null);        //没有启用动态方法调用,则setMethod为null。
        }
    }
}

 public ActionMapping getMapping(HttpServletRequest request,
        ConfigurationManager configManager) {
……
  // handle "name!method" convention.
    handleDynamicMethodInvocation(mapping, mapping.getName());  
      //动态方法调用的处理,没有开启动态方法调用则设置method为空
      String fullName = mapping.getName();                 //这里为name,总是不为空
     // Only try something if the action name is specified
    if (fullName != null && fullName.length() > 0) {
        // cut off any ;jsessionid= type appendix but allow the rails-like ;edit
        int scPos = fullName.indexOf(';');
        if (scPos > -1 && !"edit".equals(fullName.substring(scPos + 1))) {
            fullName = fullName.substring(0, scPos);
        }
        int lastSlashPos = fullName.lastIndexOf('/');
        String id = null;
        if (lastSlashPos > -1) {                //fullname中存在'/'则进入到如下流程

            // fun trickery to parse 'actionName/id/methodName' in the case of 'animals/dog/edit'
            int prevSlashPos = fullName.lastIndexOf('/', lastSlashPos - 1);
            //WW-4589 do not overwrite explicit method name
            if (prevSlashPos > -1 && mapping.getMethod() == null) {     //要求method为空
                mapping.setMethod(fullName.substring(lastSlashPos + 1)); 
          //这里进行方法设置,由于没有增加cleanupActionName函数过滤会导致在不开启动态方法效用的情况下执行恶意OGNL表达式。
                fullName = fullName.substring(0, lastSlashPos);
                lastSlashPos = prevSlashPos;
            }
            id = fullName.substring(lastSlashPos + 1);
        }
      ……
 }

经过代码分析,对红色标注处的函数参数进行OGNL表达式的过滤来即可进行漏洞修补。

但上面的解决方法只能从表面解决问题,但不能从根本上解决问题。官方意识到只要限制住DefaultActionInvocation.java的invokeAction函数中getValue的内容,就可以避免这样的问题在发生。则更新代码如下:

代码1

在DefaultActionInvocation.java的invokeAction方法中通过调用ognlUtil.callMethod限制了getValue的内容。在Ognl调用util中添加了callMethod方法,用于检查所传入的method内容是否为单独的方法调用,避免大段OGNL语句的执行。

官方目前发布的所有版本如下:

struts

目前官方主代码库中并没有发布不受影响的版本代码,这里提供一个开发版的下载地址:

https://dist.apache.org/repos/dist/dev/struts/

漏洞验证:

漏洞验证

防护方案

  • 在允许的情况下关闭REST插件的使用。
  • 修改代码,针对name和method通过cleanupActionName函数进行恶意OGNL表达式过滤。
  • 如果是受影响的版本及时升级到Apache Struts 2.3.29或2.5.1的版本,目前官方还未正式发布不受影响的版本,代码库地址:https://git-wip-us.apache.org/repos/asf?p=struts.git;a=summary
  • 建议密切关注官方新版本的代码发布,及时升级到不受影响的版本。这里提供一个开发版的下载地址:https://dist.apache.org/repos/dist/dev/struts/
  • 使用绿盟科技防护类产品(WAF/IPS/NF/SG)进行防护。
  • 已经购买了绿盟科技防护类产品服务的客户可以通过产品升级进行防护。
  • 短期服务:绿盟科技工程师现场处理。确保第一时间消除网络内相关风险点,控制事件影响范围,提供事件分析报告。
  • 中期服务:提供 3-6个月的风险监控与巡检服务。根除风险,确保事件不复发。
  • 长期服务:基金行业业务风险解决方案(威胁情报+攻击溯源+专业安全服务)。

声 明

本安全公告仅用来描述可能存在的安全问题,绿盟科技不为此安全公告提供任何保证或承诺。由于传播、利用此安全公告所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,绿盟科技以及安全公告作者不为此承担任何责任。绿盟科技拥有对此安全公告的修改和解释权。如欲转载或传播此安全公告,必须保证此安全公告的完整性,包括版权声明等全部内容。未经绿盟科技允许,不得任意修改或者增减此安全公告内容,不得以任何方式将其用于商业目的。

关于绿盟科技

北京神州绿盟信息安全科技股份有限公司(简称绿盟科技)成立于2000年4月,总部位于北京。在国内外设有30多个分支机构,为政府、运营商、金融、能源、互联网以及教育、医疗等行业用户,提供具有核心竞争力的安全产品及解决方案,帮助客户实现业务的安全顺畅运行。

基于多年的安全攻防研究,绿盟科技在网络及终端安全、互联网基础安全、合规及安全管理等领域,为客户提供入侵检测/防护、抗拒绝服务攻击、远程安全评估以及Web安全防护等产品以及专业安全服务。

北京神州绿盟信息安全科技股份有限公司于2014年1月29日起在深圳证券交易所创业板上市交易,股票简称:绿盟科技,股票代码:300369。

如果您需要了解更多内容,可以
加入QQ群:486207500、570982169
直接询问:010-68438880-8669

Spread the word. Share this post!

Meet The Author

Leave Comment