继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
通过对代码库的对比发现修复方法如下:
分析发现,修复的地方为在启用了动态方法调用(Dynamic Method Invocation)的情况下,通过cleanupActionName函数对OGNL表达式过滤,阻止恶意OGNL表达式执行。
查看Apache Structs 2.3.28.1的源文件RestActionMapper.java,发现修复的地方在函数handleDynamicMethodInvocation中,代码分析如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
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的内容,就可以避免这样的问题在发生。则更新代码如下:
在DefaultActionInvocation.java的invokeAction方法中通过调用ognlUtil.callMethod限制了getValue的内容。在Ognl调用util中添加了callMethod方法,用于检查所传入的method内容是否为单独的方法调用,避免大段OGNL语句的执行。
官方目前发布的所有版本如下:
目前官方主代码库中并没有发布不受影响的版本代码,这里提供一个开发版的下载地址:
https://dist.apache.org/repos/dist/dev/struts/
本安全公告仅用来描述可能存在的安全问题,绿盟科技不为此安全公告提供任何保证或承诺。由于传播、利用此安全公告所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,绿盟科技以及安全公告作者不为此承担任何责任。绿盟科技拥有对此安全公告的修改和解释权。如欲转载或传播此安全公告,必须保证此安全公告的完整性,包括版权声明等全部内容。未经绿盟科技允许,不得任意修改或者增减此安全公告内容,不得以任何方式将其用于商业目的。
北京神州绿盟信息安全科技股份有限公司(简称绿盟科技)成立于2000年4月,总部位于北京。在国内外设有30多个分支机构,为政府、运营商、金融、能源、互联网以及教育、医疗等行业用户,提供具有核心竞争力的安全产品及解决方案,帮助客户实现业务的安全顺畅运行。
基于多年的安全攻防研究,绿盟科技在网络及终端安全、互联网基础安全、合规及安全管理等领域,为客户提供入侵检测/防护、抗拒绝服务攻击、远程安全评估以及Web安全防护等产品以及专业安全服务。
北京神州绿盟信息安全科技股份有限公司于2014年1月29日起在深圳证券交易所创业板上市交易,股票简称:绿盟科技,股票代码:300369。
如果您需要了解更多内容,可以
加入QQ群:486207500、570982169
直接询问:010-68438880-8669