CVE-2022-39135(Apache calcite xxe)分析
漏洞影响版本:<1.32.0的所有版本
0X01:Apache calcite
Apachecacite是一个动态数据库管理框架,它自身是包含一套符合行业标准的sql解析与验证器,既然支持解析sql语句,那么就有可能存在内建函数缺陷(例如mysql低版本的load_file函数可以写入任意文件,在高版本中便默认不支持)
0X02:起因
这个CVE是因为Apache calcite中的EXISTSNODE、EXTRACTXML、XMLTRANSFORM、 EXTRACTVALUE函数支持解析xml,并且在解析xml时默认支持解析外部实体引用从而导致XXE
0X03:分析
查阅官方文档,对其有如下解释
机翻了一下:
方言特定运算符永久链接
以下运算符不在SQL标准中,并且未在Calcite的默认运算符表中启用。只有当会话启用了额外的运算符表时,它们才可用于查询。
要启用运算符表,请设置fun connect字符串参数。
“C”(兼容性)列包含值:
“b”表示Google BigQuery(连接字符串中的“fun=BigQuery”),
“h”表示Apache Hive(连接字符串中的“fun=Hive”),
“m”表示MySQL(连接字符串中的“fun=MySQL”),
“o”表示Oracle(连接字符串中的“fun=Oracle”),
‘p’表示PostgreSQL(连接字符串中的’fun=PostgreSQL’),
“s”表示Apache Spark(连接字符串中的“fun=Spark”)。
一个运算符名称可能对应于多个SQL方言,但语义不同。
大概的意思是,Apache calcite支持SQL方言,并且有b,h,m,o,p,s多种数据库模式,只用设置对应的键值对就能启动对应的方言,那我们漏洞涉及到的方法是哪一种方言呢?这里我们挑选其中一个EXTRACTVALUE来进行验证
可以看到该方法的作用是解析xml并且返回第一个文本节点的文本,该方法对应的是m,也就是mysql,要启用对这个方法的支持需要设置fun的值为mysql,如何设置该值呢?
我们通过setProperty的方法设置对应的键值对并且将其注册到calcite链接中
1 | Properties info = new Properties(); |
完整payload:
1 | import org.apache.calcite.jdbc.CalciteConnection; |
在查询获得resultSet后调用next方法时触发xml解析
跟进evaluate,在290行处直接newDocumentBuilder然后直接在291行处调用parse,没有设置关闭外部实体加载
触发dns解析
读取到任意文件
0X05:官方修复
此处的input就是我们的xml字符串,原来直接将input带入evalute中,而1.32.0版本中input经过了getDocumentNode进行处理
getDocumentNode中去new了DocumentBuilder
并且DOCUMENT_BUILDER_FACTORY.get()中已经设置了禁止加载外部实体
进而漏洞就无法触发了