1. CVE-2019-19599
源码:/ext/misc/zipfile.c,这个文件实现了一个虚拟表来读取和写入归档zip文件。
SQLite有一个表sqlite_master,包含了数据库中所有自建表的信息。
查看一个表的所有信息:pragma table_info([tablename]);
常见用法:
1 | CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip'); |
利用zipfile功能创建了一个虚表temp.zip
,然后向其中插入一条数据。其中name, data
是虚表中的两个字段,如果data
的值为NULL的话,代表插入的数据是一个目录,否则是文件。
漏洞描述:
在涉及文件名中嵌入’\0’字符的情况下,SQLite 3.30.1中的ext/misc/zipfile.c会误处理INSERT INTO的某些用法,从而导致可以由(例如)valgrind检测到内存管理错误。
调试过程:
在一个终端启动sqlite3:
再在另外一个终端查看sqlite3的进程号:48941
然后使用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
中对这一条件进行了断言设置。
但是在IN字句中,如果出现NATURAL JOIN连接两个DISTINCT子查询的情况的话,会内部设置GROUP BY这个属性,导致断言失败。
调试分析:
上面会内部设置GROUP BY这个属性的话,那么在执行IN字句优化例程函数的时候,p->pGroupBy
应该不为0.但是在调试过程中发现,无论sqlite是在添加了-DNDEBUG
参数还是没有添加的情况下,使用论文中提到的PoC来验证均发现没有改变这个属性。
下图为调试过程中的截图:
4. case study 2:Database leakage
原来这个就是CVE-2019-19959,怪我没有仔细看。
按照论文中给出的PoC来验证,感觉没有什么异常啊,只是单纯的把经过zipfile函数生成的一个zip用hex的方式显示出来了而已,而且调试过程中并没有走到漏洞的源代码处。
5. case study 3:UAF from Assertion
这个bug获得了CVE编号:CVE-2019-20218。
使用PoC验证时,sqlite直接爆语法错误。第二条sql语句需要和第三条同时输入,然后再测试第三条SQL语句。
由于第二条语句创建的是一个循环视图(创建视图v2的数据来自要创建的视图v2),会导致其pWith指针称为一个悬空指针。
但是调试到后面,导致程序崩溃的情况是在一个比较函数里面:
而且调用这个函数的地方是在这个漏洞修补处的前面,按道理在后面修补,前面同样会出问题的吧,且还没找到关于p->pWith
指针的断言语句。
而且我在加上-DNDEBUG
参数之后再来测试,同样的还是崩溃了。
后在大佬的指导下,解决了调试不能断在assert函数的地方的问题,需要再设置-DSQLITE_DEBUG
这个参数,sqlite3.c
中解释了这两个参数必须是相反的,如果注释了-DNDEBUG
且没有定义-DSQLITE_DEBUG
那么就会再次将-DNDEBUG
设为1,所以解决方法就是注释掉-DNDEBUG
的同时定义-DSQLITE_DEBUG
。