研究人員在Operation PowerFall攻擊活動中發現了一個0 day漏洞——CVE-2020-1380。該漏洞是一個JS中的UAF漏洞,補丁已於2020年8月11日發布。
IE 11遠程代碼執行漏洞利用
最近發現的在野IE 0 day漏洞利用主要是依賴JavaScript 引擎jscript.dll中CVE-2020-0674、CVE-2019-1429、CVE-2019-0676和 CVE-2018-8653等漏洞。而CVE-2020-1380是jscript9.dll中的漏洞,從IE 9開始默認使用。
CVE-2020-1380是JIT 優化引發的UAF漏洞,是由於即時編譯代碼中缺乏必要的檢查導致的。觸發該漏洞的PoC代碼如下:
function func(O, A, F, O2) // execute abp.valueOf() and write by dangling pointerA[5] = O;};// prepare objectsvar an = new ArrayBuffer(0x8c);var fa = new Float32Array(an);// compile funcfunc(1, fa, 1, {});for (var i = 0; i
漏洞利用使用對象abp和valueOf()方法。該方法在對象轉化為浮點數時執行,但是該方法中有釋放ArrayBuffer的代碼。為了防止值保持在釋放的對象的內存中,JS引擎在保持該值之前需要檢查對象的狀態。為了安全地轉化和保持浮點值,JScript9.dll會使用函數Js::TypedArray
int Js::TypedArray::BaseTypedDirectSetItem(Js::TypedArray *this, unsigned int index, void *object, int reserved)return 1;}double Js::JavascriptConversion::ToNumber(void *object, struct Js::ScriptContext *context)elseelse{*(float *)buffer = *(double *)(object->value);}}}}
以下是Js::JavascriptConversion::ToFloat_Helper() 函數的代碼:
void Js::JavascriptConversion::ToFloat_Helper(void *object, float *buffer, struct Js::ScriptContext *context){*buffer = Js::JavascriptConversion::ToNumber_Full(object, context);}
與翻譯模式不同的是,在實時編譯的代碼中,並不會檢查ArrayBuffer,其內存會被釋放然後在valueOf()函數被調用時重新聲明。此外,攻擊者可以控制返回值要寫入的index。當PoC 中的arguments.length = 0;和arguments.push(O2); 被替換為arguments[0] = O2;時,Js::JavascriptConversion::ToFloat_Helper()並不會觸發漏洞,因為調用會被禁用,也不會執行到valueOf()的調用。
為了確保函數func()即時編譯,漏洞利用執行了該函數0x10000次,只有在func()函數多執行一次後才會觸發漏洞。為了釋放ArrayBuffer,漏洞利用會濫用Web Workers API。函數postMessage() 會用來序列號對象並發送。轉化的對象被釋放後,在當前腳本環境中會無法使用。當ArrayBuffer被釋放時,漏洞利用會通過模擬Sleep()函數的使用來觸發垃圾回收:檢查Date.now()和之前保存的值之間的時間間隔。之後,漏洞利用會聲明含有整數數組的內存。
for (var i = 0; i
在創建了大量的數組後,IE就會分配IE定製堆首先使用的新的LargeHeapBlock 對象。LargeHeapBlock對象會保存為數組分配的緩存地址。如果成功獲得期望的內存布局,漏洞就會用0覆寫LargeHeapBlock的偏移量0x14,即分配的區塊數。
jscript9.dll x86的LargeHeapBlock結構
之後,漏洞利用會分配大量的數組,並設置為漏洞利用初始階段準備的另一個數組。然後該數組會設置為null,漏洞利用會調用CollectGarbage()函數。導致堆的碎片重新整理,修改後的LargeHeapBlock和相關的數組緩存都會釋放。此時,漏洞利用會創建大量的整數數組來重新聲明之前釋放的數組緩存。新創建的數組在index 0處有一個值,並通過到之前釋放的數組的指針來檢查漏洞利用是否成功。
for (var i = 0; i
因此,漏洞利用會創建兩個指向相同位置的緩存的JavascriptNativeIntArray對象。因此可以提取對象的地址,甚至創建新構造的對象。漏洞利用使用了這些原語來創建了一個構造的DataView 對象,並獲取了進程整個地址空間的讀寫權限。
利用任意讀寫原語的構造可以繞過Control Flow Guard (CFG)和實現代碼執行。漏洞利用使用Array的vftable指針來獲得jscript9.dll的模塊基地址。然後分析jscript9.dll的PE header來獲取Import Directory Table的地址,並解析其他模塊的基地址。目標是找到函數VirtualProtect()的地址,這會將shellcode變得可以執行。之後,漏洞利用會在jscript9.dll中搜索2個籤名。這些籤名對應Unicode字符串split的地址和函數JsUtil::DoublyLinkedListElement
之後進入下一個階段。漏洞利用會執行split()方法,並提供一個含有覆寫的valueOf()方法的對象作為限制參數。函數Js::JavascriptString::EntrySplit()在執行過程中valueOf()方法也會執行,漏洞利用會搜索線程的棧來找到返回的地址,並shellcode放置在之前的緩存中,獲取其地址,並通過覆寫函數的返回地址來構造一個return-oriented programming (ROP)鏈來執行shellcode。
下一個階段
Shellcode是加到shellcode的PE模塊的反射型DLL加載器。該模塊非常小,整個功能位於單獨的函數中。並在臨時文件夾中創建一個名為ok.exe的文件,並將遠程代碼執行漏洞利用中的另一個可執行文件的內容寫入。之後,執行ok.exe。
ok.exe可執行文件中含有GDI Print / Print Spooler API中任意指針簡接引用漏洞CVE-2020-0986的權限提升漏洞利用。該漏洞利用可以使用進程間通信來實現splwow64.exe進程的任意內存讀寫,並用它來實現splwow64.exe進程的代碼執行,繞過CFG 和EncodePointer保護。漏洞利用以及兩個可仔細文件都會嵌入到其資源中。第一個可執行文件會寫入磁碟中(CreateDC.exe),然後用來創建漏洞利用所需的設備環境(device context)。第二個可執行文件名為PoPc.dll,如果漏洞利用成功,splwow64.exe就會執行。
來自splwow64.exe的惡意PowerShell 命令執行
PoPc.dll的主要功能位於單個函數中,執行一個編碼的PowerShell命令來從www[.]static-cdn1[.]com/update.zip下載文件,並以upgrader.exe保存到臨時文件中並執行。
參考及來源:https://securelist.com/ie-and-windows-zero-day-operation-powerfall/97976/