黑帽SEO

黑帽SEO技术:利用单个SQLite漏洞破解多个软件

  这次与大家一个国内安全厂商的议题《一石多鸟:利用单个SQLite漏洞破解多个软件》。

  0x01 什么是内存破坏漏洞

  SQLite是一款轻型数据库,是遵守ACID的关系型数据管理系统,它包含在一个相对小的C库中。作为一款嵌入式数据库,他因占用的资源非常低,数据处理速度快等优点被Andriod、WebKit等流行软件采用。

  说起SQLite的内存破坏漏洞,共分为两种类型,一是由SQLite数据库的文件格式引起的内存损坏漏洞,如CVE-2015-7036,CVE-2017-10989,另一个是SQLite解析器触发的sql语句中的错误。CVE-2015-3414,CVE-2015-3415。

  提起CVE-2015-7036,fts3_tokenizer是一个绕不开的话题。这是发生在Apple iOS 8.4以前版本和 OS X 10.10.4版本以前的漏洞,原因是内置的SQLite的fts3_tokenizer函数存在任意命令执行漏洞,远程攻击者可以通过SQL命令执行任意指令或导致系统崩溃,拒绝服务。让我们来一起看看这个能让号称最安全的苹果系统都中招的fts3_tokenizer到底是何方神圣。

  sqlite中支持fts表(full-text search的简称),fts3其实是sqlite的一个扩展模块,是虚拟表模块,允许用户使用 MATCH ‘keyword’ 查询而非 LIKE ‘%keyword%’ 子串匹配的方式实现全文检索。在实现全文搜索的过程中,对原始内容进行分词是一个必须的过程。SQLite内置的simple和porter分词器只能支持ASCII字符的英文分词,为满足不同语言的需求,SQLite 3.7.13开始引入unicode61分词器以支持unicode,并提供给开发者自行添加分词器的接口。

  0x02 fts3_tokenizer的两种烹饪方式

  sqlite在fts3_tokenizer.h中提供了各种接口供用户自定义分词器,但其并未提供c函数供用户来注册自定义的分词器,分词器的注册必须使用sql语句来完成。

  官方提供了两种fts3_tokenizer函数的使用方式,这两种方式便产生了两种漏洞:

  1、SELECT fts3_tokenizer();

  参数中的tokenizer-name是分词器的名称,该用法的返回值是指定名字分词器的sqlite3_tokenizer_module 结构体指针,以 blob 类型表示16进制的一个大端序的内存地址。该用法本来是用来检查分词器是否被注册。但是同时我们也发现,如果是探测一个已经存在的分词器返回值是一个内存地址。在 fts3.c 中可以看到 SQLite3 默认注册了内置分词器 simple 和 porter:

  以 simple 分词器为例,其注册的指针指向静态区的 simpleTokenizerModule。

  通过获得这个指针,获得 sqlite3 的基地址,根据不同版本调整偏移量,可以计算绕过 ASLR保护机制:

  Offset2lib攻击:

  这里提一下关于绕过ASLR保护机制的相关内容:

  ASLR(Address Space Layout Randomization),地址空间格局的随机化,就是用来防范Ret2libc攻击手段的另一个重要的安全特性。在你知道目标代码或数据定位的前提下,它可以变成一种规避攻击的技术。正因为黑客并不知道整个地址空间的布局,ASLR技术变得极为有效。只有当可执行程序编译为PIE时(地址无关可执行文件),才能最大限度地从ASLR技术那里获得保护,因为其所有组成部分都是从随机地址加载的。

  然而,当可执行文件被编译成PIE之后,GNU/Linux下的ASLR实现的过程中,会出现一个名为Offset2lib安全漏洞,其专门用于绕过在GNU/Linux下如ASLR之类的对于普通漏洞的常用防护。

  正常情况下,可能需要大概五步进行攻击,攻击的流程总结如下:

  提取静态信息

  暴力获取saved-IP部分

  计算应用基址

  计算offset2lib常量

  获得内存映射区域

  首先,我们的攻击对目标程序和其执行环境做一个离线分析。利用标准的缓冲区溢出漏洞来暴力获取被ASLR隐藏的保存在栈里的应用代码的saved-IP地址(应用地址),这多亏了目标的fork服务器结构。一旦我们获得了目标应用的完整地址,应用的基址就能被计算出来。最后一步则是对整个库做内存映射,这将决定于目标GNU/Linux的版本。获得隐藏的未明信息后,利用ROP应用获得远程shell是非常容易的。

  因为fts3_tokenizer好心的提醒了我们基址地址,甚至不需要前三步的计算,通过union或者盲注,我们可以获取到这个基地址信息。

  计算出目标库的offset2lib值,它会因系统的不同而不同,但相互之间有很大的相似性。获得这些offset2lib的值有一个迅捷的办法,那就是本地执行该应用,打印出偏移量。offset2lib并不决定于应用本身,我们需要为特定Linux系统版本量身计算。

  libc(Linux下的ANSI C的函数库。 ANSI C是基本的C语言函数库,包含了C语言最基本的库函数)的基址都可以通过可执行文件基址减去offset2lib值来计算:

  Libc_base = App_base - offset2lib

  获取到libc的内存地址之后的目标就是获取shell了。可以借助ROP(现代栈溢出利用技术基础)来实现,本文就不详细介绍了。

  2、SELECT fts3_tokenizer(,);

  这里的sqlite3_tokenizer_module ptr表示一个指向sqlite3_tokenizer_module结构的指针并且编码为SQL blob。这种用法用来注册新的分词器,在SQL下执行此形式语句,即可注册一个的分词器。没错,这里就是把指针当成参数直接放进SQL语句中了,这个指针指向一个 sqlite3_tokenizer_module 结构体,前文已经提到其中包含数个回调函数指针,注册完成分词器后,SQLite3 在处理一些 SQL 查询时将会执行分词器的回调函数以获得结果。

  攻击者构造出一个结构体之后,获取到该结构体的内存地址,并使用 SQL 注入等手段让目标注册构造好的“分词器”,再通过 SQL 触发特殊回调就可以实现劫持 IP 寄存器,执行任意代码。接下来进一步分析这个攻击面是否可以被利用。

  现在来尝试触发 xCreate 回调执行任意代码。在SQLite3 控制台输入如下查询即可导致段错误:

  用gdb查看崩溃的上下文:

  rax 注册时提交的指针参数,cast将blob类型数据转换为指针,SQLite 完全没有对指针做任何有效性检查,直接进行了回调的调用。其对应源代码位于 ext/fts3/fts3_tokenizer.c 的 sqlite3Fts3InitTokenizer 函数:

  整理一下思路,整个攻击流程应该是这样的:

  首先利用fts3_tokenizer的第一种方式,查询到sqlite基地址,注意结果是大端序。根据 select sqlite_version() 函数泄漏的版本信息调整偏移量,执行 PRAGMA soft_heap_limit 语句布置需要 call 的目标指令地址,向一个已知内存地址写入一个函数指针,然后这个地址转换为blob类型,作为fts3_tokenizer 函数的第二个参数,进而注册了一个“分词器”,最后通过创建虚拟表,触发 xCreate 回调函数,导致eip劫持,允许远程攻击者执行任意代码。

  0x03亡羊补牢犹未晚

  虽然这不是 SQLite 的漏洞,但滥用这一特性可能导致应用程序产生攻击面。

  禁用这一特性可以起到缓解的效果。比如Andriod甚至是SQLite自己都在3.11版本就采用了直接禁用这种方式。

  重写函数也不为是一个不错的办法,十分流行的WebKit也曾提供选择禁用Web SQL Database作为本地数据库,它采用的语言就是SQLite,但已经被W3C标准移除了。现在WebKit也重写了函数。

  但是只是简单的白名单过滤并不是一个优秀的处理方式,Safari浏览器采用sqlite3_set_authorizer()用来授权SQL语句行为,并通过白名单控制了可以执行的SQL语句,但CVE-2015-3659中明确说了如何绕过白名单,同样执行任意代码,或者导致拒绝服务,系统崩溃。

  总结一下修复和处理的方式:

  如果用不到全文检索,可通过关闭 SQLITE_ENABLE_FTS3 / SQLITE_ENABLE_FTS4 / SQLITE_ENABLE_FTS5 选项禁用之,或者使用 Amalgamation 版本编译;

  如果需要使用 MATCH 检索,但不需要支持多国语言(即内置分词器可以满足要求),找到 ext/fts3/fts3.c 中注释掉如下一行代码关闭此函数:

  && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, “fts3_tokenizer”))

  使用 SQLite3 的 Authorization Callbacks 设置访问控制

  0x04参考链接

  [1] 特性还是漏洞?滥用 SQLite 分词器

  [2]《一石多鸟:利用单一的SQLITE 漏洞攻击大量软件》

  [3] SQLite

  [4] Offset2lib攻击测试:看我如何全面绕过64位Linux的内核防护


本文链接:/portal/article/index/id/172/cid/2.html
赞 ()

相关推荐

0.315035s