CVE-2012-0158 MSCOMCTL控件漏洞分析


参考:http://bbs.pediy.com/showthread.php?t=149957(样本是此链接提供的样本)

环境 :

  xp sp3 / word2007


运行样本后,会弹出计算器

因为此类型的exp的shellcode 在运行的时候都会释放文件,释放文件时需要调用kernel32.dll 中的GetFileSize函数来判断需要释放的文件,

所以在windbg开始调试poc时,在GetFileSize函数下断点,bu kernel32!GetFileSize,但是word运行时会调用很多次GetFileSize,直接下断点的话,会执行很多次。

我们知道漏洞出现在MSCOMCTL.OCX中,因此我们可以等待加载MSCOMCTL.OCX后在对GetFileSize下断点

sxe ld:MSCOMCTL.OCX

加载 MSCOMCTL.OCX模块时会断下来

0:000> g
(278.288): Unknown exception - code e0000002 (first chance)
ModLoad: 27580000 27685000   C:\WINDOWS\system32\MSCOMCTL.OCX
eax=00000000 ebx=00000000 ecx=03c30000 edx=7c92e4f4 esi=00000000 edi=00000000
eip=7c92e4f4 esp=0012392c ebp=00123a20 iopl=0         nv up ei ng nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000296
ntdll!KiFastSystemCallRet:
7c92e4f4 c3              ret
0:000> bp kernel32!GetFileSize
0:000> bl
 0 e 7c810b07     0001 (0001)  0:**** kernel32!GetFileSize

然后g运行程序,程序停在GetFileSize处,

然后gu跳出GetFileSize函数,程序已经进入shellcode区域

观察右下角堆栈调用,可知上层调用位于

MSCOMCTL!DllGetClassObject+0x41cc6 处
u MSCOMCTL!DllGetClassObject+0x41cc6
MSCOMCTL!DllGetClassObject+0x41cc6:
275c8a0a 8bf0            mov     esi,eax
275c8a0c 83c40c          add     esp,0Ch
275c8a0f 85f6            test    esi,esi
275c8a11 7c3d            jl      MSCOMCTL!DllGetClassObject+0x41d0c (275c8a50)
275c8a13 837df800        cmp     dword ptr [ebp-8],0
275c8a17 8b7d08          mov     edi,dword ptr [ebp+8]
275c8a1a 742a            je      MSCOMCTL!DllGetClassObject+0x41d02 (275c8a46)
275c8a1c 83650c00        and     dword ptr [ebp+0Ch],0

地址位于275c8a0a 处。猜测出现问题的地方就在此附近。

IDA打开MSCOMCTL.OCX模块,定位到275c8a0a处附近

.text:275C89C7 ; int __stdcall sub_275C89C7(int, BSTR bstrString)
.text:275C89C7 sub_275C89C7    proc near               ; CODE XREF: sub_275C8807+10p
.text:275C89C7                                         ; sub_275E7004+11p ...
.text:275C89C7
.text:275C89C7 var_14          = dword ptr -14h
.text:275C89C7 dwBytes         = dword ptr -0Ch
.text:275C89C7 var_8           = dword ptr -8
.text:275C89C7 var_4           = dword ptr -4
.text:275C89C7 arg_0           = dword ptr  8
.text:275C89C7 bstrString      = dword ptr  0Ch
.text:275C89C7
.text:275C89C7 ; FUNCTION CHUNK AT .text:275D3085 SIZE 0000001D BYTES
.text:275C89C7
.text:275C89C7                 push    ebp
.text:275C89C8                 mov     ebp, esp
.text:275C89CA                 sub     esp, 14h
.text:275C89CD                 push    ebx
.text:275C89CE                 mov     ebx, [ebp+bstrString]
.text:275C89D1                 push    esi
.text:275C89D2                 push    edi
.text:275C89D3                 push    0Ch             ; dwBytes
.text:275C89D5                 lea     eax, [ebp+var_14]
.text:275C89D8                 push    ebx             ; lpMem
.text:275C89D9                 push    eax             ; int
.text:275C89DA                 call    __keyfun
.text:275C89DF                 add     esp, 0Ch
.text:275C89E2                 test    eax, eax
.text:275C89E4                 jl      short loc_275C8A52
.text:275C89E6                 cmp     [ebp+var_14], 6A626F43h
.text:275C89ED                 jnz     loc_275D3085
.text:275C89F3                 cmp     [ebp+dwBytes], 8
.text:275C89F7                 jb      loc_275D3085
.text:275C89FD                 push    [ebp+dwBytes]   ; dwBytes
.text:275C8A00                 lea     eax, [ebp+var_8]
.text:275C8A03                 push    ebx             ; lpMem
.text:275C8A04                 push    eax             ; int
.text:275C8A05                 call    __keyfun
.text:275C8A0A                 mov     esi, eax
.text:275C8A0C                 add     esp, 0Ch
.text:275C8A0F                 test    esi, esi
.text:275C8A11                 jl      short loc_275C8A50
.text:275C8A13                 cmp     [ebp+var_8], 0
.text:275C8A17                 mov     edi, [ebp+arg_0]
.text:275C8A1A                 jz      short loc_275C8A46
.text:275C8A1C                 and     [ebp+bstrString], 0
.text:275C8A20                 lea     eax, [ebp+bstrString]
.text:275C8A23                 push    ebx             ; int
.text:275C8A24                 push    eax             ; len
.text:275C8A25                 call    sub_275C8A59
.text:275C8A2A                 mov     esi, eax
.text:275C8A2C                 pop     ecx
.text:275C8A2D                 test    esi, esi
.text:275C8A2F                 pop     ecx
.text:275C8A30                 jl      short loc_275C8A50
.text:275C8A32                 push    [ebp+bstrString] ; strIn
.text:275C8A35                 lea     ecx, [edi-24h]
.text:275C8A38                 call    sub_27585BE7
.text:275C8A3D                 push    [ebp+bstrString] ; bstrString
.text:275C8A40                 call    ds:SysFreeString
.text:275C8A46
.text:275C8A46 loc_275C8A46:                           ; CODE XREF: sub_275C89C7+53j
.text:275C8A46                 cmp     [ebp+var_4], 0
.text:275C8A4A                 jnz     loc_275D308F
.text:275C8A50
.text:275C8A50 loc_275C8A50:                           ; CODE XREF: sub_275C89C7+4Aj
.text:275C8A50                                         ; sub_275C89C7+69j ...
.text:275C8A50                 mov     eax, esi
.text:275C8A52
.text:275C8A52 loc_275C8A52:                           ; CODE XREF: sub_275C89C7+1Dj
.text:275C8A52                                         ; sub_275C89C7+A6C3j
.text:275C8A52                 pop     edi
.text:275C8A53                 pop     esi
.text:275C8A54                 pop     ebx
.text:275C8A55                 leave
.text:275C8A56                 retn    8
.text:275C8A56 sub_275C89C7    endp

发编译如下:

int __stdcall sub_275C89C7(int a1, BSTR bstrString)
{
  BSTR v2; // ebx@1
  int result; // eax@1
  int v4; // esi@4
  int v5; // [sp+Ch] [bp-14h]@1
  SIZE_T dwBytes; // [sp+14h] [bp-Ch]@3
  int v7; // [sp+18h] [bp-8h]@4
  int v8; // [sp+1Ch] [bp-4h]@8

  v2 = bstrString;
  result = _keyfun((int)&v5, bstrString, 0xCu);
  if ( result >= 0 )
  {
    if ( v5 == 1784835907 && dwBytes >= 8 )
    {
      v4 = _keyfun((int)&v7, v2, dwBytes);
      if ( v4 >= 0 )
      {
        if ( !v7 )
          goto LABEL_8;
        bstrString = 0;
        v4 = sub_275C8A59((UINT)&bstrString, (int)v2);
        if ( v4 >= 0 )
        {
          sub_27585BE7(bstrString);
          SysFreeString(bstrString);
LABEL_8:
          if ( v8 )
            v4 = sub_275C8B2B(a1 + 20, v2);
          return v4;
        }
      }
      return v4;
    }
    result = -2147418113;
  }
  return result;
}

int __cdecl _keyfun(int a1, LPVOID lpMem, SIZE_T dwBytes)
{
  LPVOID v3; // ebx@1
  int result; // eax@1
  LPVOID v5; // eax@3
  int v6; // esi@4
  int v7; // [sp+Ch] [bp-4h]@1
  LPVOID lpMema; // [sp+1Ch] [bp+Ch]@3

  v3 = lpMem;
  result = (*(int (__stdcall **)(LPVOID, int *, signed int, _DWORD))(*(_DWORD *)lpMem + 12))(lpMem, &v7, 4, 0);
  if ( result >= 0 )
  {
    if ( v7 == dwBytes )
    {
      v5 = HeapAlloc(hHeap, 0, dwBytes);
      lpMema = v5;
      if ( v5 )
      {
        v6 = (*(int (__stdcall **)(LPVOID, LPVOID, SIZE_T, _DWORD))(*(_DWORD *)v3 + 12))(v3, v5, dwBytes, 0);
        if ( v6 >= 0 )
        {
          qmemcpy((void *)a1, lpMema, dwBytes);
          v6 = (*(int (__stdcall **)(LPVOID, _UNKNOWN *, SIZE_T, _DWORD))(*(_DWORD *)v3 + 12))(
                 v3,
                 &unk_27632368,
                 ((dwBytes + 3) & 0xFFFFFFFC) - dwBytes,
                 0);
        }
        HeapFree(hHeap, 0, lpMema);
        result = v6;
      }
      else
      {
        result = -2147024882;
      }
    }
    else
    {
      result = -2147418113;
    }
  }
  return result;
}

根据上结果可以大致判断,异常出现原因是因为对字符串长度判断出问题,导致溢出。

下面使用OD具体跟踪下情况:

因为MSCOMCTL.OCX 并不在word运行起来就加载,所以一开始是不能对MSCOMCTL.OCX中的地址进行断点设置的,但是一般模块的加载都是是哟用函数LoadLibraryA函数的,

因此可以在LoadLibraryA下断点(不要一开始就下断点,因为word运行时会加载很多断点)

OD加载may.doc, F9运行,出现提示(之前运行过样本)

此时MSCOMCTL.OCX模块还未被加载,如下:

此时在LoadLibraryA函数下断点,然后点击上图提示中的打开word

此时程序断在LoadLibraryA 函数处,在查看程序加载模块,此时MSCOMCTL.OCX已经被加载

此时就可以在MSCOMCTL.OCX模块中下断点了,由windbg可知,异常点在MSCOMCTL!DllGetClassObject+0x41cc6附近

跟踪可知,第二次执行问call 275C876D 后,函数的返回地址被覆盖,参见下两图

进入函数:

第二次执行问call 275C876D后,

可见堆栈上的返回地址已经被7ffa4512覆盖了,此地址即是jmp esp的地址。

如果你进入275C876D 函数中,清楚的看到数据拷贝的过程(也就IDA反编译中的那两个关键函数)


知道覆盖地址,知道覆盖点,剩下的就是shellcode了


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值