溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何進(jìn)行Safari信息泄露漏洞的分析

發(fā)布時(shí)間:2021-11-18 16:50:06 來源:億速云 閱讀:174 作者:柒染 欄目:網(wǎng)絡(luò)管理

今天就跟大家聊聊有關(guān)如何進(jìn)行Safari信息泄露漏洞的分析,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

前言

Javascript中的數(shù)組和數(shù)組對(duì)象一直都是編程人員優(yōu)化的主要目標(biāo),一般來說,數(shù)組只會(huì)包含一些基本類型數(shù)據(jù),比如說32位整數(shù)或字符等等。因此,每個(gè)引擎都會(huì)對(duì)這些對(duì)象進(jìn)行某些優(yōu)化,并提升不同元素類型的訪問速度和密集型表示。

在JavaScriptCore中,JavaScript引擎是在WebKit中實(shí)現(xiàn)的,其中每一個(gè)存儲(chǔ)在對(duì)象中的元素都代表著一個(gè)IndexingType值,一個(gè)8位整數(shù)代表一套Flag組合,具體的參數(shù)定義可以在IndexingType.h中找到。接下來,引擎會(huì)檢測一個(gè)對(duì)象中indexing的類型,然后決定使用哪一條快速路徑,其中最重要的一種indexing類型就是ArrayWithUndecided,它表示的是所有元素均為未定義(undefined),而且沒有存儲(chǔ)任何實(shí)際的值。在這種情況下,引擎為了提升性能,會(huì)讓這些元素保持未初始化。

分析

下面,我們一起看一看舊版本中實(shí)現(xiàn)Array.prototype.concat的代碼(ArrayPrototype.cpp):

EncodedJSValueJSC_HOST_CALL arrayProtoPrivateFuncConcatMemcpy(ExecState* exec){    ...     unsigned resultSize =checkedResultSize.unsafeGet();    IndexingType firstType =firstArray->indexingType();    IndexingType secondType =secondArray->indexingType();    IndexingType type =firstArray->mergeIndexingTypeForCopying(secondType); // [[ 1 ]]    if (type == NonArray ||!firstArray->canFastCopy(vm, secondArray) || resultSize >=MIN_SPARSE_ARRAY_INDEX) {        ...    }     JSGlobalObject* lexicalGlobalObject =exec->lexicalGlobalObject();    Structure* resultStructure =lexicalGlobalObject->arrayStructureForIndexingTypeDuringAllocation(type);    if(UNLIKELY(hasAnyArrayStorage(resultStructure->indexingType())))        return JSValue::encode(jsNull());    ASSERT(!lexicalGlobalObject->isHavingABadTime());    ObjectInitializationScopeinitializationScope(vm);    JSArray* result =JSArray::tryCreateUninitializedRestricted(initializationScope, resultStructure,resultSize);    if (UNLIKELY(!result)) {        throwOutOfMemoryError(exec, scope);        return encodedJSValue();    }     if (type == ArrayWithDouble) {        [[ 2 ]]        double* buffer =result->butterfly()->contiguousDouble().data();        memcpy(buffer,firstButterfly->contiguousDouble().data(), sizeof(JSValue) *firstArraySize);        memcpy(buffer + firstArraySize,secondButterfly->contiguousDouble().data(), sizeof(JSValue) *secondArraySize);    } else if (type != ArrayWithUndecided) { ...

這個(gè)函數(shù)主要用來判斷結(jié)果數(shù)組[[1]]的indexing類型,我們可以看到,如果indexing類型為ArrayWithDouble,它將會(huì)選擇[[2]]作為快速路徑。接下來,我們看一看:

mergeIndexingTypeForCopying的實(shí)現(xiàn)代碼,這個(gè)函數(shù)主要負(fù)責(zé)在Array.prototype.concat被調(diào)用時(shí),判斷結(jié)果數(shù)組的indexing類型:

inlineIndexingType JSArray::mergeIndexingTypeForCopying(IndexingType other){    IndexingType type = indexingType();    if (!(type & IsArray && other& IsArray))        return NonArray;     if (hasAnyArrayStorage(type) ||hasAnyArrayStorage(other))        return NonArray;     if (type == ArrayWithUndecided)        return other; [[ 3 ]] ...

我們可以看到在這種情況下,有一個(gè)輸入數(shù)組的indexing類型為ArrayWithUndecided,結(jié)果indexing類型將會(huì)是另一個(gè)數(shù)組的indexing類型。因此,如果我們我們用一個(gè)indexing類型為ArrayWithUndecided的數(shù)組和另一個(gè)indexing類型為ArrayWithDouble的數(shù)組去調(diào)用Array.prototype.concat方法的話,我們將會(huì)按照快速路徑[[2]]運(yùn)行,并將兩個(gè)數(shù)組進(jìn)行拼接。

這段代碼并不能保證這兩個(gè)“butterfly”(JavaScript引擎攻擊技術(shù)里的一種概念,詳情請(qǐng)參考【這篇文章】)在代碼調(diào)用memcpy之前能夠正確初始化。這也就意味著,如果我們能夠找到一條允許我們創(chuàng)建一個(gè)未初始化數(shù)組并將其傳遞給Array.prototype.concat的代碼路徑,那我們就能夠在堆內(nèi)存中擁有一個(gè)包含了未初始化值的數(shù)組對(duì)象了,而且它的indexing類型還不是ArrayWithUndecided。從某種程度上來說,這個(gè)安全問題跟lokihardt在2017年報(bào)告的一個(gè)    舊漏洞有些相似,只不過利用方式不同。

在創(chuàng)建這種數(shù)組對(duì)象時(shí),可以利用NewArrayWithSize DFG JIT的操作碼來實(shí)現(xiàn),在對(duì)FTLLowerDFGToB3.cpp中FTL所實(shí)現(xiàn)的allocateJSArray操作碼進(jìn)行分析之后,我們可以看到這個(gè)數(shù)組將會(huì)包含未初始化的值。引擎根本不需要對(duì)數(shù)組進(jìn)行初始化,因?yàn)檫@個(gè)數(shù)組的indexing類型為ArrayWithUndecided。

ArrayValuesallocateJSArray(LValue publicLength, LValue vectorLength, LValue structure,LValue indexingType, bool shouldInitializeElements = true, boolshouldLargeArraySizeCreateArrayStorage = true){    [ ... ]    initializeArrayElements(       indexingType,       shouldInitializeElements ?m_out.int32Zero : publicLength, vectorLength,       butterfly); ...voidinitializeArrayElements(LValue indexingType, LValue begin, LValue end, LValuebutterfly){     if (begin == end)        return;     if (indexingType->hasInt32()) {        IndexingType rawIndexingType =static_cast<IndexingType>(indexingType->asInt32());        if (hasUndecided(rawIndexingType))            return;  // [[ 4 ]]

語句new Array(n)在被FTL JIT編譯時(shí)將會(huì)觸發(fā)[[4]],然后返回一個(gè)indexing類型為ArrayWithUndecided的數(shù)組,其中就包含未初始化的元素。

漏洞利用

清楚了之前所介紹的漏洞原理之后,想必觸發(fā)這個(gè)漏洞也并非難事:我們可以不斷重復(fù)調(diào)用一個(gè)使用new Array()方法來創(chuàng)建數(shù)組的函數(shù),然后調(diào)用concat方法將這個(gè)數(shù)組和一個(gè)只包含double類型數(shù)據(jù)的數(shù)組進(jìn)行拼接。在調(diào)用夠足夠次數(shù)之后,F(xiàn)TL編譯器將會(huì)對(duì)其進(jìn)行編譯。

這份【漏洞利用代碼】可以利用這個(gè)漏洞來泄漏一個(gè)目標(biāo)對(duì)象的內(nèi)存地址,實(shí)現(xiàn)機(jī)制是通過我們所創(chuàng)建的對(duì)象進(jìn)行內(nèi)存噴射,在觸發(fā)這個(gè)漏洞之后,我們就能夠從代碼所返回的數(shù)組中找到目標(biāo)對(duì)象的地址了。

這個(gè)漏洞目前已經(jīng)在iOS 12和macOS Mojave的最新版本(Safari)中修復(fù)了,該漏洞的CVE編號(hào)為CVE-2018-4358。

看完上述內(nèi)容,你們對(duì)如何進(jìn)行Safari信息泄露漏洞的分析有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI