欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

CVE-2019-8603:Safari沙盒逃逸&LPE深入分析

来源:本站整理 作者:佚名 时间:2019-06-03 TAG: 我要投稿

在这篇文章中,我们将对漏洞CVE-2019-8603进行分析。简而言之,这是一个存在于Dock以及com.apple.uninstalld服务中的堆越界读取漏洞,该漏洞将导致攻击者调用CFRelease并在macOS上实现Safari浏览器沙盒逃逸,最终获取到目标设备的root权限。
漏洞CVE-2019-8606将允许攻击者通过kextutil中的竞争条件来以root权限实现内核代码执行,再配合上qwertyoruiopz和bkth提供的WebKit漏洞(远程代码执行漏洞),攻击者就可以彻底破坏掉Safari本身的安全机制,并攻陷目标用户的操作系统
不过别担心,刚才提到的这两个漏洞苹果公司的安全技术人员都已经在macOS 10.14.5版本中成功修复了。
 
漏洞分析
此前,本人正在开发一款基于代码覆盖导向的模糊测试工具,并且在用这款工具对AXUnserializeCFType进行测试时发现了本文的主角,也就是漏洞CVE-2019-8606。但根据我之前的接触,这个函数本质上其实是一个简单的解析器,而且它曾在去年的Pwn2Own大会上曾出现,但当时没有人发现这个函数竟然存在漏洞。
翻了一下文档之后,我才发现我搞错了。这个函数是CoreFoundation对象序列化的另一个代码实现函数,它属于HIServices框架中的一个组件,而且代码存储在对应的dylib库中。
这个函数能够进行序列化处理的其中一种对象类型为CFAttributedString,这种字符串中,每一个字符都跟一个CFDictionary有关联,其中存储了跟对应字符串相关的任意描述信息(属性)。这些属性可以是颜色、字体或其他用户需要标注的信息。对于我们来说,我们要的就是代码执行了。
为了帮助大家更直观地了解这种特性,我们专门给出了这种特性所对应的数据结构:
// from CFAttributedString.c
struct __CFAttributedString {
CFRuntimeBase base;
CFStringRef string;
CFRunArrayRef attributeArray; //
};
// from CFRunArray.c
typedef struct {
CFIndex length;
CFTypeRef obj;
} CFRunArrayItem;
typedef struct _CFRunArrayGuts { / Variable sized block. /
CFIndex numRefs; / For “copy on write” behavior /
CFIndex length; / Total count of values stored by the CFRunArrayItems in list /
CFIndex numBlocks, maxBlocks; / These describe the number of CFRunArrayItems in list /
CFIndex cachedBlock, cachedLocation; / Cache from last lookup /
CFRunArrayItem list[0]; / GCC /
} CFRunArrayGuts;
/ Definition of the CF struct for CFRunArray /
struct CFRunArray {
CFRuntimeBase base;
CFRunArrayGuts guts;
};
1、 从索引0(index 0)开始,长度为11, 属性标识为“bold”;
2、 从索引11(index 11)开始,长度为4,无属性标识;
3、 从索引15(index 15)开始,长度为4, 属性标识为“italic”;
很明显,这种特性还要求维护一些不会发生变化的“因素”,比如说字符以及单词之间的空隙等等。
反序列化函数cfAttributedStringUnserialize有两条执行路径。第一条非常简单:它会读取一个字符串,然后使用属性字典(NULL)来调用CFAttributedStringCreate。没错,有意思的地方在于该函数的第二条执行路径:它首先会解析一个字符串,以及一个包含了范围和关联字典的列表,然后调用内部函数_CFAttributedStringCreateWithRuns:
CFAttributedStringRef _CFAttributedStringCreateWithRuns(
CFAllocatorRef alloc,
CFStringRef str,
const CFDictionaryRef attrDictionaries,
const CFRange *runRanges,
CFIndex numRuns) { …
比如说,这种特性可以在内部使用三组CFRunArrayItems来表示字符串“attribution is hard”:

解析器将会根据检测结果来确保字典内容以及字符串能够匹配,但是它无法判断实际的字符串范围信息,而且_CFAttributedStringCreateWithRuns同样也无法做到这一点:
for (cnt = 0; cnt CFMutableDictionaryRef attrs = CFAttributedStringCreateAttributesDictionary(alloc, attrDictionaries[cnt]);
__CFAssertRangeIsWithinLength(len, runRanges[cnt].location, runRanges[cnt].length); //
CFRunArrayReplace(newAttrStr->attributeArray, runRanges[cnt], attrs, runRanges[cnt].length);
CFRelease(attrs);
}
而且最终的正式发布版本中也没有针对此项判断的断言。因此,攻击者将能够使用完全可控的range以及newLength值来调用CFRunArrayReplace。
void CFRunArrayReplace(CFRunArrayRef array, CFRange range, CFTypeRef newObject, CFIndex newLength) {
CFRunArrayGuts *guts = array->guts;
CFRange blockRange;
CFIndex block, toBeDeleted, firstEmptyBlock, lastEmptyBlock;
// [[ 1 ]]
// ??? if (range.location + range.length > guts->length) BoundsError;
if (range.length == 0) return;
if (newLength == 0) newObject = NULL;
// [...]
/* This call also sets the cache to point to this block */
// [[ 2 ]]
block = blockForLocation(guts, range.location, &blockRange);
guts->length -= range.length;
/* Figure out how much to delete from this block */
toBeDeleted = blockRange.length - (range.location - blockRange.location);
if (toBeDeleted > range.length) toBeDeleted = range.length;
/* Delete that count */
// [[ 3 ]]
if ((guts->list[block].length -= toBeDeleted) == 0) FREE(guts->list[block].obj);

首先看代码段[[ 1 ]]部分,很明显,代码开发人员想要尝试对传入的参数有效性进行验证,但实际上它并没有更改函数签名并返回任何错误信息。

[1] [2]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载