Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探
1.本文一共1514個字 28張圖 預計閱讀時間10分鐘
2.本文作者erfze 屬於Gcow安全團隊複眼小組 未經過許可禁止轉載
3.本篇文章是文章Internet Explorer漏洞分析(三)[下]——CVE-2014-6332的前置知識,對vbscrip.dll元件進行逆向分析,以及VBScript資料型別,陣列,VarType函式,LenB函式詳細分析,並介紹VBS指令碼除錯技巧
4.本篇文章十分適合漏洞安全研究人員進行交流學習
5.若文章中存在說得不清楚或者錯誤的地方 歡迎師傅到公眾號後臺留言中指出 感激不盡
近來分析Internet Explorer歷史漏洞,遂對VBScript指令碼解析引擎進行研究,具體環境如下:
OS版本:Windows 7 Service Pack 1
Internet Explorer版本:8.0.7601.17514
vbscript.dll版本:5.8.7601.17514
0x01 變數
VBScript中僅有一種資料型別——Variant。其結構定義如下:
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,Pi
Name="Ethon"
Age=27
Hex=&h80000000
Pi=3.1415926
'隱式宣告
Hello="ABC123"
賦值對應函式為vbscript!AssignVar
,於該函式處設斷,檢視其引數:
0x400C
表示VT_VARIANT
:
判斷pvargSrc—>vt
值(具體數值可自行分析,不贅述),若均不滿足,執行如下語句:
簡單來說,即VariantCopyInd(&pvarDest, pvargSrc)
——>copy pvarDest
to pvarg
:
隱式宣告變數其pvarg
全為零:
0x02 陣列
陣列儲存結構由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
結構定義如下:
typedef struct tagSAFEARRAYBOUND {
ULONG cElements;
LONG lLbound;
} SAFEARRAYBOUND, *LPSAFEARRAYBOUND;
陣列定義及賦值操作:
Dim stu_name(3)
stu_name(0)="Alan"
stu_name(1)="Susan"
stu_name(2)="Lisa"
stu_name(3)="Mary"
VBS中陣列下標由0開始,陣列元素個數為n+1(Dim array_name(n)
)。另一種定義陣列方法:
Dim stu_name
stu_name=Array("Alan","Susan","Lisa","Mary")
對應函式為vbscript!MakeArray
:
傳遞給函式的引數有二——cDims
對應維數,VAR
對應n。cDims
應介於1-64:
先來看一維陣列的建立:
為rgsabound
結構各欄位賦值:
之後則直接呼叫SafeArrayCreate
函式進行建立,各引數含義可參閱[Microsoft Docs——SafeArrayCreate]https://docs.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-safearraycreate 。建立完成:
為陣列元素賦值則直接將該元素所在記憶體偏移傳遞給vbscript!AssignVar
:
下面來看看二維陣列(Dim stu_name(2,3)
)建立過程:
可以看到陣列各維大小於記憶體中並列儲存,之後呼叫VAR::PvarGetTypeVal
逐一讀取為rgsabound
中cElements
欄位賦值:
各維大小於記憶體中由最高維——>最低維儲存,故讀取時首先計算出v3
變數指向最低維大小所在記憶體偏移,之後遞減。建立完成:
Redim
語句用於重新定義陣列大小:
'定義一維動態陣列
Dim MyArray()
'重新定義該陣列大小
ReDim MyArray(3)
MyArray(0) = "A"
MyArray(1) = "B"
MyArray(2) = "C"
MyArray(3) = "C"
再次呼叫vbscript!MakeArray
過程如下:
而在重新定義時加上Preserve
關鍵字用於保留之前元素:
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"
其對應vbscript!RedimPreserveArray
函式:
為psaboundNew
各欄位賦值完成後傳遞給SafeArrayRedim
函式:
0x03 可用於除錯時函式
IsEmpty(var)
對應vbscript!VbsIsEmpty
,其第三個引數對應var
。一例:
<!doctype html>
<html>
<head>
</head>
<body>
<script LANGUAGE="VBScript">
dim a
a = &h1234
IsEmpty(a)
</script>
</body>
</html>
IsObject(var)
對應vbscript!VbsIsObject
,同樣,其第三個引數對應var
。一例:
<!doctype html>
<html>
<head>
</head>
<body>
<script LANGUAGE="VBScript">
dim a
a = &h1234
IsObject(a)
</script>
</body>
</html>
在除錯時可藉助這兩個函式以確定變數值或記憶體位置。
0x04 VarType函式
<!doctype html>
<html>
<head>
</head>
<body>
<script LANGUAGE="VBScript">
dim a
a = &h1234
VarType(a)
</script>
</body>
</html>
VarType
對應vbscript!VbsVarType
,其呼叫GetVarType
函式獲取型別值並完成賦值操作:
引數1用於儲存型別值,引數2為VarType
引數:
GetVarType
函式呼叫PvarGetVarVal
——判斷型別值是否為0x4A
或0x0C
:
之後與0x09
進行比較,若不是則直接返回物件進而獲取vt
值:
由VbsVarType
函式完成最終賦值給引數1操作:
0x05 LenB函式
<!doctype html>
<html>
<head>
</head>
<body>
<script LANGUAGE="VBScript">
On Error Resume Next
Dim length,a
a=1.12345678901235
length=LenB("Hello")
length=LenB(a)
</script>
</body>
</html>
該函式用於返回儲存字串位元組大小,其對應vbscript!VbsLenB
。引數為字串時,該函式先是call VAR::BstrGetVal
,返回pbstrVal
:
之後call cbLengthBstr
返回長度:
引數為變數時, VAR::BstrGetVal
函式呼叫VAR::PvarConvert
,將其內容轉換為字串:
之後再進行計算:
cbLengthBstr
函式功能僅是讀取字串儲存位置之前4位元組內容,該內容為字串長度:
0x06 參閱連結