频道澳门葡京手机版网址
登录注册
澳门葡京手机版网址 > 安全 > 网络安全 > 正文

针对CVE-2015-2545漏洞研究分析

2017-04-15 10:46:00           
收藏   我要投稿

1. 概述

针对CVE-2015-2545漏洞研究分析。这是一种MSOffice漏洞,允许通过使用特殊的 Encapsulated PostScript (EPS)图形文件任意实行代码。这种漏洞于2015年3月被发现,漏洞未修补情况持续了4个月。之后,MicroSoft发布了修复补丁(MS15-099),解决了这一安全问题。

漏洞发布时间:2015-09-08

漏洞更新时间:2015-09-08

影响系统

微软 Office 2007 SP3微软 Office 2010 SP2微软 Office 2013 SP1微软 Office 2013 RT SP1微软 Office for Mac 2011微软 Office for Mac 2016微软 Office Compatibility Pack SP3

漏洞信息

微软 Office是一款MicroSoft发布的办公处理应用套件。

微软 Office处理EPS文件存在内存破坏,允许攻击者构建恶意文件,诱使应用解析,可使应用程序崩溃或实行任意代码。

用户可参考如下厂商提供的安全补丁以修复该漏洞: https://technet.microsoft.com/library/security/ms15-099

2. 样本来源

通过`推特`搜索`cve-2015-2545`得到相关信息,筛选信息得到其哈希值`哈希值:375e51a989525cfec8296faaffdefa35`,之后谷歌搜索其哈希值,最后在` https://www.hybrid-analysis.com/`得到样本。

3. 分析

3.1 漏洞成因以及利用

当EPS在处理`字典类型(dict)`的`copy操作`时,将会接受拷贝方的`键值对`,并且将自身空间数据全部删除,然后再重新分配一个空间进行数据拷贝(正常情况下字典拷贝时只对要拷贝的元素进行操作,而不影响其它元素)。而EPS在处理`forall操作`时,当处理类型为`字典(dict)`时,`forall`逐个处理字典(dict)中的每个`键值对`,`forall`会获得`当前键值对`的`内容`以及一个`ptrNext指针`,并指向下一个要处理的键值对,并将键(key)和值(value)的内容放到`操作栈`中,然后进行`forall的处理过程(proc)`,处理完后`仍保留ptrNext指针`以此来处理下一个键值对。如果在`forall`处理过程中有字典的`拷贝(copy)`操作,copy操作会将`键值对`条目`全部删除`,而forall的ptrNext指针仍`存在`,这时`ptrNext`就变成一个`野指针`,只要精心构造指针指向的数据,就可以达到利用效果。该样本利用方式为通过该野指针最终构造出一个起始地址为0x0,大小为0x7fffffff的`string对象`,这样就可以在该空间内作`任意`的`读写`操作以及后期的`ROP,Shellcode`的利用操作。

3.2 测试环境

1. 微软 Windows [版本 6.1.7601] 旗舰版sp1 简体中文 x862. Windows Debugger Version 6.12.0002.633 X863. IDA6.8.150423 (32-bit)4. OllyDbg 1.05. Notepad++6. 微软 Office Word 2007(12.0.6612.1000) SP3 MSO(12.0.6607.10000)

3.3 调试方向

此样本从3个方面来进行调试分析,第一个调试方向:定位最简单可以得到信息的位置`ROP`,第二个方向则为重点方向:产生`野指针的位置`,第三个方向:`Rop`+`Shellocde`,共3个方向进行调试分析。

3.4 调试分析-CreateFile入手[第一个方向]

1.通过Windbg打开样本,直接运行,可以发现样本在临时目录文件夹下进行创建文件操作,创建文件顺序:plugin.dll > igfxe.exe,之后,直接想到的是在`ZwCreateFile`下断点【此断点位置不太好,因为word在打开的时候不断的跑CreateFile,但通过追溯可以找到自己想要的内容】。

\

图1

2.回溯找到`ROP`,`图2`call则为`rop`call,测试方式,自己在相应call下断点,单步跟踪即可,关于rop,换栈空间的操作以及后面的shellcode这里先不详细分析,自己可以单步跟踪即可。

\

图1

\

图2

3.5 调试分析-野指针产生过程[第二个方向]

3.5.1 简易例子说明UAF

此过程比较复杂,需要了解“PostScript”语法,可以下载<>来学习;大家还要了解下关于`UAF`的简单的常识,何为`UAF`?就是字面意思“释放后重新使用“,例子如下:

#include #include #include void *pfunc1() { printf("testn"); } typedef struct Object1_struct{ int flag; void (*pfunc1)(); char message[4]; }OBJECT1; typedef struct Object2_struct{ int flag; int flag2; char *welcome; }OBJECT2; int main() { int i; OBJECT1 *pObject1; OBJECT2 *pObject2; pObject1 = (OBJECT1 *)malloc(sizeof(OBJECT1));//init struct pObject1->flag = 1; //pObject1->pfunc1(); //pObject1->message = "this is first create!"; free(pObject1); /*forget pObject1 = NULL*/ for(i=0;i<1000;i++) { pObject2 = (OBJECT2 *)malloc(sizeof(OBJECT2));//heap spray pObject2->flag=2; pObject2->flag2=4; pObject2->welcome = "AAAA"; } /*fill pointer*/ if(pObject1 != NULL) pObject1->pfunc1(); return 0; }

3.5.2 优化PostScript

了解上面的常识之后大家需要定位漏洞出现的位置,大家知道此漏洞出现的位置是在forall操作里面发生的,这个时候可以看下word文件中镶嵌的iamge1.eps文件,从文件可以看出代码都被挤压成一起了,很不方便观看这些代码,只能手动对关键代码更改`[图2]`所示

\

图1

\

图2

3.5.3 定位EPS样本文件关键位置

从代码上大家最直观发现的是`<00000000ff030000030000000000000000000000444444440005000000000000000000>`这一串东西,具体是什么大家现在先不需要考虑,然后大家可以看到forall操作{}里好多其他代码,其中就包含了copy的操作,这个位置就是导致漏洞产生的地方,那大家怎么去定位呢?动态调试,栈回溯的方式这个有点坑,大概你跟一天也跟不到吧,因为里面操作特别多,要知道这里面每个操作都是一个函数,所以回溯的方法不太可取,这个时候就需要用到IDA,直接使用IDA打开漏洞模块,打开之后大家应该想到,既然是操作,那么应该跟函数一样有带字符串的名字,那么大家是不是可以通过IDA–>shitf+f12【字符串窗口】–>查找forall这个函数呢?大家用`alt+t`查找下,果然,有了大家想要的东西`图1`,大家跟进去,发现有个地方在引用`图2`,大家继续跟进去,直接定位到了`forall函数“图3`,同理可得,大家可以定位到`copy`的函数与其他关键函数,然后动态调试跟踪即可。

\

图1

\

图2

\

图3

3.5.4 关键函数断点位置

首先大家在关键几个位置下断点,通过IDA得到偏移地址,直接Windbg or OD 定位相应位置即可,这里我用的是Windbg下断点,下面列出的断点是我调试了很多次所记录下的断点,大部分的断点我都给下了主要为了了解下代码流程方便观看,其实刚刚开始调试只需要在forall一处下断点即可,先了解其结构在观察其做法,大家先断第一个`forall`的位置

<`EPSIMP32!RegisterPercentCallback+0x4526`> 0 e 6822bcc6 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x4664 ".printf "forall_value_key_pNext"" 1 e 6823cbe4 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x15582 ".printf "dict1_dict2_Copy"" 2 e 6823a4f0 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x12e8e ".printf "dict1_dict2_copy_2"" 3 e 6821a0e8 0001 (0001) 0:**** EPSIMP32+0x1a0e8 ".printf "_copy_delete "" 4 e 6823cd89 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x15727 ".printf"copy_memcpy "" 5 e 6823ca58 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x153f6 ".printf"_exch_fun_"" 6 e 6823d592 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x15f30 ".printf"_put_fun_"" 7 e 6823d73c 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x160da ".printf"_PutInterVal_fun_"" 8 e 68230313 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x8cb1 ".printf"_BytesavailabelFun_"" 9 e 6823d8f5 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x16293 ".printf"_StringFun_"" 10 e 682312e6 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x9c84 ".printf"_ShowFun_"" 11 e 6823d830 0001 (0001) 0:**** EPSIMP32!RegisterPercentCallback+0x161ce ".printf"memcpy_putinterval_"" 12 e 6820cff5 0001 (0001) 0:**** EPSIMP32+0xcff5 ".printf"memcpy_put_bitshift_and_add_""

3.5.5 关于forall操作函数

大家通过ida可以观察forall是个`条件分支的语句`,通过查询《PLRM2.PDF》得到关于forall的说明,大约有4种情况,不过可以看出“array proc”与“packedarray proc”是一样的类型都是数组类型,其它两种类型分别是字典类型与字符串类型,验证方式直接在image.eps文件中添加实验代码即可验证。

\

图1

\

图2

3.5.6 字典对象处理流程

关键的函数为forall在处理dict的过程,大家在第三个语句块首部分下断点<`EPSIMP32!RegisterPercentCallback+0x4664`>,观察断点,入栈了3个参数,调用一函数,那么大家需要思考下这三个参数是什么,通过查询<>,大家得到关键性的资料,[`图2`]上面说如果第一个操作是字典类型,那么它会入栈一个`key`和一个`数据`,这里类似哈希表的形式,通过一个key可以迅速得到对应的数值;为什么`图1`我写`pNext`,通过`图3`大家可以判断其内容是否为null,则`lea eax, [ebp-14]`eax取出来的是个指针,所以这里这个名字主要是方便识别其为指针所定。

\

图1

\

图2

\

图3

3.5.7 对象结构解析

关于第一个CALL所做的事情,大致可以分为3个方面,给PNEXT附值,给KEY赋值,给VALUE赋值,这里说的简单,里面的功能CALL需要自己手动调试下做好记录更加方便理解是如何赋值的过程,这里直接说下是如何得到的这些数值,首先看下`ECX`所对应的内容`图1`所示,其中`+0X8`偏移的位置是循环遍历的次数,相当于一个`INDEX`也可以说是个`界限值`,里面的CALL循环条件的范围就是 `400`, 其中`+0XC`的位置`8`表示`KEY`的个数,为什么,如`图2`所示,那么关于`+0X0`偏移的位置则是个`基址`的意思,所有的结果都是通过[基址+偏移*X]的形式得到相应的数据,`图3`表示第一个`KEY1`中的内容,同时`2B4`则为下标,通过基址+下标*4即可获取第一个KEY1对应内容的地址,这0x28个字节就是个结构体,大致内容如下所示,正好可以跟大家的数据一一对应,不过这里还是需要`多跟几遍`才会更加明白`结构`的情况,当跑完第一个CALL之后的内存情况如图4所示。

\

图1

\

图2

\

图3

struct {   dword * pNext; //指向下个结构体   dword dwIndex; //下标   ps_obj key; //key   ps_obj value; //数据   }kv_pair_element;   struct PostScript object {   dword type;//类型   dword attr; //属性   dword value1; //数据   dword value2; //数据   }ps_obj;

\

图4

00030000[类型] 00000000[属性] 000001ff[数据] 04f32ea4[数据]00000300[类型] 00000000[属性] 04f69db0[数据] 04f32ea4[数据]04f8fd98[pNext]

3.5.8 释放空间函数分析

第二call,第三call,为同一call,在对key与value进行操作,copy到其他位置,之后的`PROC`则为重点call,此call则实行`forall`的所有的操作,大家只需要在copy函数的位置下断点即可得到出发漏洞的位置,然后大家单步跟踪即可,这里可以先用ida观察下copy的大致流程,然后通过动态的方式更好的去跟踪大家想要的数据,由于copy的函数块比较大,动态调试起来也不是特别容易,我这里跟的时候是每个call都跟进去了,很费时间,但肯定可以找到想要的函数数据的,这里我直接给下偏移<`EPSIMP32!RegisterPercentCallback+0x12e8e`>,如`图1`所示为释放过程的函数<`EPSIMP32+0x1a0e8`>,这个释放的过程可以仔细观察下,还记得最开始的时候的this指针所指向的内容吗?[[this]],记得第一个call的时候,大家获取KEY1-KEY8都是存在以[[this]]为基址,然后加上一个偏移得到这些数据,第一次的循环delete也是从[[this]]为基址开始遍历,判断是否为null,不是空则delete,那么最后这正片空间都被delete了,这个的范围也是大家刚刚进入第一个call的时候的一个下标`400`,循环结束之后,delete this,并且清空`+0x0`, `+0x8`,就是清空key的个数。

\

图1

\

图2(释放:dict1 copy dict2—>释放dict2过程)

上一篇:互联网安全:格式化字符串漏洞分析
下一篇:Django的两个url跳转漏洞分析:CVE-2017-7233&7234
相关文章
图文推荐

关于大家 | 联系大家 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 澳门葡京手机版网址_澳门新莆京娱乐_www.88807.com - 点此进入--致力于做实用的IT技术学习网站

XML 地图 | Sitemap 地图