Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探
Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探
1.本文一共1514個字 28張圖 預計閱讀時間10分鐘2.本文作者erfze 屬于Gcow安全團隊復眼小組 未經(jīng)過許可禁止轉(zhuǎn)載3.本篇文章是文章Internet Explorer漏洞分析(三)[下]——CVE-2014-6332的前置知識,對vbscrip.dll組件進行逆向分析,以及VBScript數(shù)據(jù)類型,數(shù)組,VarType函數(shù),LenB函數(shù)詳細分析,并介紹VBS腳本調(diào)試技巧4.本篇文章十分適合漏洞安全研究人員進行交流學習5.若文章中存在說得不清楚或者錯誤的地方 歡迎師傅到公眾號后臺留言中指出 感激不盡
近來分析Internet Explorer歷史漏洞,遂對VBScript腳本解析引擎進行研究,具體環(huán)境如下:
?OS版本:Windows 7 Service Pack 1?Internet Explorer版本:8.0.7601.17514?vbscript.dll版本:5.8.7601.17514
0x01 變量
VBScript中僅有一種數(shù)據(jù)類型——Variant。其結(jié)構(gòu)定義如下:
typedef struct tagVARIANT {union {struct {VARTYPE vt;WORD wReserved1;WORD wReserved2;WORD wReserved3;union {LONGLONG llVal;LONG lVal;BYTE bVal;SHORT iVal;FLOAT fltVal;DOUBLE dblVal;VARIANT_BOOL boolVal;VARIANT_BOOL __OBSOLETE__VARIANT_BOOL;SCODE scode;CY cyVal;DATE date;BSTR bstrVal;IUnknown *punkVal;IDispatch *pdispVal;SAFEARRAY *parray;BYTE *pbVal;SHORT *piVal;LONG *plVal;LONGLONG *pllVal;FLOAT *pfltVal;DOUBLE *pdblVal;VARIANT_BOOL *pboolVal;VARIANT_BOOL *__OBSOLETE__VARIANT_PBOOL;SCODE *pscode;CY *pcyVal;DATE *pdate;BSTR *pbstrVal;IUnknown **ppunkVal;IDispatch **ppdispVal;SAFEARRAY **pparray;VARIANT *pvarVal;PVOID byref;CHAR cVal;USHORT uiVal;ULONG ulVal;ULONGLONG ullVal;INT intVal;UINT uintVal;DECIMAL *pdecVal;CHAR *pcVal;USHORT *puiVal;ULONG *pulVal;ULONGLONG *pullVal;INT *pintVal;UINT *puintVal;struct {PVOID pvRecord;IRecordInfo *pRecInfo;} __VARIANT_NAME_4;} __VARIANT_NAME_3;} __VARIANT_NAME_2;DECIMAL decVal;} __VARIANT_NAME_1;} VARIANT;
其中VARTYPE可參閱[Microsoft Docs——VARIANT Type Constants]https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/3fe7db9f-5803-4dc4-9d14-5425d3f5461f。例:
'顯式聲明Dim Name,Age,Hex,PiName="Ethon"Age=27Hex=&h80000000Pi=3.1415926'隱式聲明Hello="ABC123"
賦值對應(yīng)函數(shù)為vbscript!AssignVar,于該函數(shù)處設(shè)斷,查看其參數(shù):

0x400C表示VT_VARIANT:

判斷pvargSrc—>vt值(具體數(shù)值可自行分析,不贅述),若均不滿足,執(zhí)行如下語句:

簡單來說,即VariantCopyInd(&pvarDest, pvargSrc)——>copy pvarDest to pvarg:

隱式聲明變量其pvarg全為零:

0x02 數(shù)組
數(shù)組存儲結(jié)構(gòu)由SAFEARRAY定義:
typedef struct tagSAFEARRAY {USHORT cDims;USHORT fFeatures;ULONG cbElements;ULONG cLocks;PVOID pvData;SAFEARRAYBOUND rgsabound[1];} SAFEARRAY;
其中各字段含義可參閱[Microsoft Docs——SAFEARRAY]https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray ,SAFEARRAYBOUND結(jié)構(gòu)定義如下:
typedef struct tagSAFEARRAYBOUND {ULONG cElements;LONG lLbound;} SAFEARRAYBOUND, *LPSAFEARRAYBOUND;
數(shù)組定義及賦值操作:
Dim stu_name(3)stu_name(0)="Alan"stu_name(1)="Susan"stu_name(2)="Lisa"stu_name(3)="Mary"
VBS中數(shù)組下標由0開始,數(shù)組元素個數(shù)為n+1(Dim array_name(n))。另一種定義數(shù)組方法:
Dim stu_namestu_name=Array("Alan","Susan","Lisa","Mary")
對應(yīng)函數(shù)為vbscript!MakeArray:

傳遞給函數(shù)的參數(shù)有二——cDims對應(yīng)維數(shù),VAR對應(yīng)n。cDims應(yīng)介于1-64:

先來看一維數(shù)組的創(chuàng)建:

為rgsabound結(jié)構(gòu)各字段賦值:

之后則直接調(diào)用SafeArrayCreate函數(shù)進行創(chuàng)建,各參數(shù)含義可參閱[Microsoft Docs——SafeArrayCreate]https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraycreate 。創(chuàng)建完成:

為數(shù)組元素賦值則直接將該元素所在內(nèi)存偏移傳遞給vbscript!AssignVar:

下面來看看二維數(shù)組(Dim stu_name(2,3))創(chuàng)建過程:

可以看到數(shù)組各維大小于內(nèi)存中并列存儲,之后調(diào)用VAR::PvarGetTypeVal逐一讀取為rgsabound中cElements字段賦值:

各維大小于內(nèi)存中由最高維——>最低維存儲,故讀取時首先計算出v3變量指向最低維大小所在內(nèi)存偏移,之后遞減。創(chuàng)建完成:

Redim語句用于重新定義數(shù)組大小:
'定義一維動態(tài)數(shù)組Dim MyArray()'重新定義該數(shù)組大小ReDim MyArray(3)MyArray(0) = "A"MyArray(1) = "B"MyArray(2) = "C"MyArray(3) = "C"
再次調(diào)用vbscript!MakeArray過程如下:

而在重新定義時加上Preserve關(guān)鍵字用于保留之前元素:
Dim MyArray()ReDim MyArray(3)MyArray(0) = "A"MyArray(1) = "B"MyArray(2) = "C"MyArray(3) = "D"ReDim Preserve MyArray(5)MyArray(4) = "E"MyArray(5) = "F"
其對應(yīng)vbscript!RedimPreserveArray函數(shù):

為psaboundNew各字段賦值完成后傳遞給SafeArrayRedim函數(shù):

0x03 可用于調(diào)試時函數(shù)
IsEmpty(var)對應(yīng)vbscript!VbsIsEmpty,其第三個參數(shù)對應(yīng)var。一例:
<!doctype html><html lang="en"><head></head><body><script LANGUAGE="VBScript">dim aa = &h1234IsEmpty(a)</script></body></html>

IsObject(var)對應(yīng)vbscript!VbsIsObject,同樣,其第三個參數(shù)對應(yīng)var。一例:
<!doctype html><html lang="en"><head></head><body><script LANGUAGE="VBScript">dim aa = &h1234IsObject(a)</script></body></html>

在調(diào)試時可借助這兩個函數(shù)以確定變量值或內(nèi)存位置。
0x04 VarType函數(shù)
<!doctype html><html lang="en"><head></head><body><script LANGUAGE="VBScript">dim aa = &h1234VarType(a)</script></body></html>
VarType對應(yīng)vbscript!VbsVarType,其調(diào)用GetVarType函數(shù)獲取類型值并完成賦值操作:

參數(shù)1用于存儲類型值,參數(shù)2為VarType參數(shù):

GetVarType函數(shù)調(diào)用PvarGetVarVal——判斷類型值是否為0x4A或0x0C:

之后與0x09進行比較,若不是則直接返回對象進而獲取vt值:

由VbsVarType函數(shù)完成最終賦值給參數(shù)1操作:

0x05 LenB函數(shù)
<!doctype html><html lang="en"><head></head><body><script LANGUAGE="VBScript">On Error Resume NextDim length,aa=1.12345678901235length=LenB("Hello")length=LenB(a)</script></body></html>
該函數(shù)用于返回存儲字符串字節(jié)大小,其對應(yīng)vbscript!VbsLenB。參數(shù)為字符串時,該函數(shù)先是call VAR::BstrGetVal,返回pbstrVal:

之后call cbLengthBstr返回長度:

參數(shù)為變量時, VAR::BstrGetVal函數(shù)調(diào)用VAR::PvarConvert,將其內(nèi)容轉(zhuǎn)換為字符串:

之后再進行計算:

cbLengthBstr函數(shù)功能僅是讀取字符串存儲位置之前4字節(jié)內(nèi)容,該內(nèi)容為字符串長度:

0x06 參閱鏈接
?[Microsoft Docs——SAFEARRAY structure]https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray?[Microsoft Docs——VARIANT structure]https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant?[Microsoft Docs——VARIANT Type Constants]https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/3fe7db9f-5803-4dc4-9d14-5425d3f5461f?[Microsoft Docs——SafeArrayCreate]https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraycreate?[Microsoft Docs——DECIMAL structure]https://docs.microsoft.com/en-us/windows/win32/api/wtypes/ns-wtypes-decimal-r1
