飞速星空
资讯首页>> dll下载免费下载
利用污点分析工具发现word2003的bug——word2003转换wps文件时堆溢出(20180129)
[更新:2018-02-21 23:54:13] [浏览:6次]

最近一直在搞文档类漏洞的自动化挖掘分析(污点分析)。

测试那个污点分析工具的时候用的是word2003,测试过程中也算有一些微小的成果。

这个bug,一方面是感觉利用不起来,一方面是word2003也略老了。不过放出来给像我一样的初学者学习一个,提高姿势水平,应该还是有一些微小的意义的。

其实我也不知道这个bug有没有人公开过,感觉无从考证。如果发现有人已经公开过了的话,欢迎告诉我一声。(现在是2018年1月29日,留个时间戳)

现在漏洞挖掘好像分两派。一派是静态分析,这一派似乎比较讲究对代码的理解,对文件格式、写一个格式等的理解;另一派是fuzzing,这一派初期就是暴力穷举,现在也引入了类似符号执行等的方法来辅助fuzzing工具理解程序或者格式,加速测试过程。

静态分析太慢了,太累了,太苦了;fuzzing又有点像撞大运。

那么,有没有一种自动化的“静”态或“动”态方法呢?自动地去理解文件格式,代码流程。

从编译器的角度来看,一个程序就是一个CFG,程序运行就是根据用户输入,在CFG中走不同的路径;漏洞就是某个特定的路径。

所以,如果我们能自动发现某一部分数据,对应哪一部分代码,那么就相当于自动化理解了文件格式和代码实现。

本文所用的污点分析工具就是根据这个思路写的。

说完最近的理解进入正题。

这个bug简单描述就是word2003打开wps文件,自动转换格式时,可能发生堆溢出。

样本是用wps2003创建的,随便输入几个字符,保存的时候,选择 works 6.0 & 7.0 (*.wtf) 格式。再把wtf后缀改成wps后缀。

这种文件好像是office约定的某种复合文件格式,具体其实我也不懂。

用7z可以解开文件,可以发现里面有几个子文件。

堆溢出就出现在处理CONTENTS这部分内容的代码里。

测试环境为win7 sp1,下载站下载的word2003(应该没有补丁)。

用污点分析工具分析之后得到某一部分的代码流程如下:

1. 读取文件内容

在WKCVQD01.DLL动态库中

.text:610945ADpushedi

.text:610945AEpushebx

.text:610945AFpushesi

.text:610945B0calldwordptr[eax+0Ch]

在610945B0处,调用ole32的一个复合文件格式读取函数读取512字节的CONTENTS子文件的内容到缓冲区(记为bufferContents)

HRESULT__stdcallCExposedStream::Read(CExposedStream*this,void*pb,unsignedintcb,unsignedint*pcbRead)

2. 复制32字节的文件头到栈缓冲区上

函数调用栈如下

signedint__cdeclvul2_my_61091C99(DWORD*a1)

copy_my_61093B4F(*a1,&Dst,0x20u,0)//*a1就是上面的bufferContents;&Dst是栈缓冲区

memcpy(Dst,i,v10);

vul2_my_61091C99

.text:61091CA3movebx,[ebp+arg_0]

.text:61091CA6pushesi

.text:61091CA7pushedi

.text:61091CA8moveax,[ebx]

.text:61091CAAmoveax,[eax]

.text:61091CACmovesi,[eax+10h]

.text:61091CAFcmpesi,200h

.text:61091CB5jlloc_61091F43

.text:61091CBBxoredi,edi

.text:61091CBDmov[eax+14h],edi

.text:61091CC0pushedi;int

.text:61091CC1leaeax,[ebp+Dst]//[ebb-40]

.text:61091CC4push20h;Size

.text:61091CC6pusheax;Dst

.text:61091CC7pushdwordptr[ebx];//bufferContents

.text:61091CC9callcopy_my_61093B4F

copy_my_61093B4F

.text:61093BD6pushebx;Size

.text:61093BD7jnzshortloc_61093BE9

.text:61093BD9push[ebp+Src];Src

.text:61093BDCpush[ebp+Dst];Dst

.text:61093BDFcallmemcpy

3. 文件头偏移16字节位置的dword内容解释为内存分配大小参数

allocCnt1=allocCnt0;

dstMem=(signed__int16*)malloc_my__61094BBD(allocCnt1);//allocCnt1可控

.text:61091DA5push[ebp+allocCnt0];//内存分配的大小[ebp-30]

.text:61091DA8movword_6110A25C,ax

.text:61091DAEmovsxeax,[ebp+var_34]

.text:61091DB2mov[ebx+8],eax

.text:61091DB5callmalloc_my__61094BBD

ebp-40(栈缓冲区开始)到ebp-30偏移是10h(16字节)。

从代码里可以看到,我们可以控制分配的内存大小。

为了方便,这里把分配得到的内存记为dstMem

4. 文件头偏移24字节处的word内容解释为需要复制的内存大小,复制到dstMem中

copyCnt=v28;//v28就是文件头偏移24字节处的word内容

if((signedint)allocCnt0<v28)

copyCnt=allocCnt0;

copy_my_61093B4F(*v1,dstMem,copyCnt,0)//*v1就是bufferContents

.text:61091DE8movsxeax,[ebp+var_28]//[ebp-28]距离文件头[ebb-40]处24字节

.text:61091DECcmp[ebp+allocCnt0],eax

.text:61091DEFjgeshortloc_61091DF4

.text:61091DF1moveax,[ebp+allocCnt0]

.text:61091DF4

.text:61091DF4loc_61091DF4:;CODEXREF:vul2_my_61091C99+156↑j

.text:61091DF4pushecx;int

.text:61091DF5pusheax;Size

.text:61091DF6pushesi;//dstMem

.text:61091DF7pushdwordptr[ebx];//bufferContents

.text:61091DF9callcopy_my_61093B4F

可以看到从word宽度v28转到dword宽度的copyCnt用的是符号位扩展转换

.text:61091DE8 movsx eax, [ebp+var_28]

也就是如果原来的v28是0xFFFF,那么copyCnt就是0xFFFFFFFF

从代码里可以看到,在复制前,是由检查复制的大小有没有超过缓冲区大小的。

但是,这里用的是有符号数的比较。

.text:61091DEF jge short loc_61091DF4

有符号数比较没有只考虑上界,却忘记判断下界大于0。

dword a, dword b两个数

按照有符号数比较,如果b是负数(最高位为1),a是正数(最高位为0),那么b一定比a小。

但是如果在接下来的场合,比如memcpy的时候,b又被解释为无符号数,那么b一定比a大,于是就溢出了。

5. 连起来构造poc

把wps生成的文件,用010editor打开,搜索CHNKWKS。

然后把offset 16处的dword内容改为1

把offset 24处的word内容改为0xFFFF

可控的内存分配,可控的复制大小,负数绕过大小限制,然后就堆溢出了

6. 异常现场

最后,其实这些代码还真的是能反映某个时代的代码风格。

本文由看雪论坛ktkitty 原创

转载请注明来自看雪社区

热门阅读

win32下的堆管理系统

dalvik虚拟机启动及运行原理的研究

通过MITMf利用$MFT漏洞锁定局域网电脑

x64内核中的HOOK技术|拦截进程、拦截线程、拦截模块(思路)

点击阅读原文/read,

更多干货等着你~

推荐内容: