0%

SQLite漏洞调试记录

1. CVE-2019-19599

源码:/ext/misc/zipfile.c,这个文件实现了一个虚拟表来读取和写入归档zip文件。

SQLite有一个表sqlite_master,包含了数据库中所有自建表的信息。

查看一个表的所有信息:pragma table_info([tablename]);

常见用法:

1
2
CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip');
INSERT INTO temp.zip(name, data) VALUES ('dir\x00s1', NULL);

利用zipfile功能创建了一个虚表temp.zip,然后向其中插入一条数据。其中name, data是虚表中的两个字段,如果data的值为NULL的话,代表插入的数据是一个目录,否则是文件。

漏洞描述:

在涉及文件名中嵌入’\0’字符的情况下,SQLite 3.30.1中的ext/misc/zipfile.c会误处理INSERT INTO的某些用法,从而导致可以由(例如)valgrind检测到内存管理错误。

调试过程:

在一个终端启动sqlite3:

image-20200824011634623

再在另外一个终端查看sqlite3的进程号:48941

image-20200824011813218

然后使用root权限启动gdb,在编译sqlite的时候加上-g参数就可以在这里使用file命令载入调试符号表,然后再进行attach 48941就可以正常调试了。

调试分析:

当使用gdb进行附加后,原来的sqlite会进入等待状态,这个时候不能进行任何输入。找到漏洞出现的源代码处,下断点break zipfileUpdate,然后continue,就可以在sqlite的终端输入命令了。

使用next, print, x命令可以灵活查看调试过程中的变量内容,内存信息,使用set可以修改内容,由于\0字符在终端输入的时候会导致SQL语句被截掉一半的情况,所以为了形成描述中的情况,我在调试的过程中找到变量的位置并插入了’\0’字符。

而在执行zipfileUpdate的时候,对于目录名,会在目录名之后添加一个’/‘字符,而由于’\0’的截断,会导致对目录名字符串长度计数的变量nPath计算出错,原来是单纯的nPath++,这样实际的目录名长度会比nPath要小,漏洞修复后改为strlen函数来计算正确的长度。

2. CVE-2019-19317

漏洞描述:

在生成列的情况下,SQLite 3.30.1中resolve.c中的lookupName忽略了colUsed位掩码中的位,这使攻击者可以拒绝服务或可能造成未指定的其他影响。

调试分析:

调试过程和前一个漏洞一样。

由于暂时未找到触发漏洞处的代码的testcase,暂时搁置,先看论文中提到的4个Bug案例分析,再回头来看这个漏洞。

3. case study 1:A 11-year Bug

漏洞描述:

在2009年的check-in中,因为SQL语法中不允许出现GroupBy字句,所以在对IN字句进行优化的函数isCandidateForInOpt中对这一条件进行了断言设置。

image-20200903163744634

但是在IN字句中,如果出现NATURAL JOIN连接两个DISTINCT子查询的情况的话,会内部设置GROUP BY这个属性,导致断言失败。

调试分析:

上面会内部设置GROUP BY这个属性的话,那么在执行IN字句优化例程函数的时候,p->pGroupBy应该不为0.但是在调试过程中发现,无论sqlite是在添加了-DNDEBUG参数还是没有添加的情况下,使用论文中提到的PoC来验证均发现没有改变这个属性。

image-20200907083132163

下图为调试过程中的截图:

image-20200907083404723

4. case study 2:Database leakage

原来这个就是CVE-2019-19959,怪我没有仔细看。

按照论文中给出的PoC来验证,感觉没有什么异常啊,只是单纯的把经过zipfile函数生成的一个zip用hex的方式显示出来了而已,而且调试过程中并没有走到漏洞的源代码处。

image-20200907092046829

5. case study 3:UAF from Assertion

这个bug获得了CVE编号:CVE-2019-20218。

使用PoC验证时,sqlite直接爆语法错误。第二条sql语句需要和第三条同时输入,然后再测试第三条SQL语句。

image-20200907115230945

由于第二条语句创建的是一个循环视图(创建视图v2的数据来自要创建的视图v2),会导致其pWith指针称为一个悬空指针。

image-20200907115849015

但是调试到后面,导致程序崩溃的情况是在一个比较函数里面:

image-20200907164940502

而且调用这个函数的地方是在这个漏洞修补处的前面,按道理在后面修补,前面同样会出问题的吧,且还没找到关于p->pWith指针的断言语句。

而且我在加上-DNDEBUG参数之后再来测试,同样的还是崩溃了。

后在大佬的指导下,解决了调试不能断在assert函数的地方的问题,需要再设置-DSQLITE_DEBUG这个参数,sqlite3.c中解释了这两个参数必须是相反的,如果注释了-DNDEBUG且没有定义-DSQLITE_DEBUG那么就会再次将-DNDEBUG设为1,所以解决方法就是注释掉-DNDEBUG的同时定义-DSQLITE_DEBUG

image-20200920004802260