微软MS11-006 Windows Shell图形处理漏洞原理及补丁分析(上)
作者: nine8
QQ : 279933462
杂记: http://hi.baidu.com/tapeout
看微软公告说是公开的漏洞,但是网上搜了下没有找到相关的细节,应该只是发现者在POC2010演讲的话题。
这里只有POC2010演讲者摘要没有paper(http://www.powerofcommunity.net/speaker.html)于是自己尝试分析了下。
由于之前在一家IC Fabless公司从事芯片设计相关工作,打交道的最上层也只是firmware的同事, 对这块接触时间不长,相关的知识或是术语理解还很肤浅,
如果文中哪里出现那些错误,那怕是用词的偏差,还请大家不吝给小弟指出,感谢!
0x00 总体信息概要
---------------------
== 调试环境: VMware7.0 + en_windows_xp_professional_with_service_pack_3_x86
== 主要软件: MetaSploit Framwork 6.4, OllyDBG 2.0, IDA Pro 5.5
== 漏洞编号: MS11-006, CVE-2010-3970
== 相关文件: shimgvw.dll, shell32.dll
== 漏洞描述: Windows Shell 图形处理器中一个公开披露的漏洞。 如果用户查看特制缩略图,此漏洞可能允许远程执行代码。
成功利用此漏洞的攻击者可以获得与登录用户相同的用户权限。 那些帐户被配置为拥有较少系统用户权限的用户比
具有管理用户权限的用户受到的影响要小。
详见: http://www.microsoft.com/china/technet/security/bulletin/MS11-006.mspx
0x02 重现漏洞现场
--------------------
== POC/EXP : http://www.exploit-db.com/exploits/16660/
== 触发漏洞: 1) 创建文件夹,设置查看模式为缩略图。
2) 用MSF产生EXP, 指定输出到创建的文件夹内,进入文件夹,弹出calc, explorer提示关闭。
3) 知道现象后,用MSF产生用于Debug的POC, 进行调试分析。
0x03 确定问题所在
--------------------
== 定位范围: 将OD attach 到explorer.exe进程, 中断在: (ecx过大,超出申请stack,从而照成stack溢出.)
----------------------------------------------------------
5CB1FC42: REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
----------------------------------------------------------
==动态调试: 1). shimgvw.dll的导出函数ConvertDIBSECTIONToThumbnail的子函数CreateSizeDIBSECTION: 在判断ecx的传入参数时,
通过有符号判断最大上限,但是数据复制是用无符号数, 从而导致stack溢出.
2). 漏洞函数被调用的大概过程 (这里只是doc的,没有包含media的, media类似)
explorer.exe --> [ntdll.dll/shlwapi.dll/browseui.dll等] --> shell32.dll(CExtractImageTask:Run) -->
shimgvw.dll(CDocThumb::Extract) --> shimgvw.dll(GetDocFileThumbnail) -->
shimgvw.dll(ConvertDIBSECTIONToThumbnail --> shimgvw.dll(CreateSizeDIBSECTION)
0x04 倒推分析Stream细节:
----------------------
静态逆向分析:
== 函数: CreateSizeDIBSECTION (shimgvw.dll)
.text:5CB1FB63 sub esp, 430h ; 开辟0x430栈空间, 之后溢出的地方
.text:5CB1FB69 mov eax, [ebp+arg_10]
...... ; 此处省略98个字, :)
.text:5CB1FB72 call ds:__imp__GetDC@4 ; GetDC(x)
.text:5CB1FB78 cmp eax, ebx
.text:5CB1FB7A mov [ebp+hDC], eax
.text:5CB1FB7D jz loc_5CB1FD05
.text:5CB1FB83 push edi
.text:5CB1FB84 push eax ; hdc
.text:5CB1FB85 call ds:__imp__CreateCompatibleDC@4 ; 获取设备无关内存环境句柄
...... ; 中间省略N个字
.text:5CB1FBAA lea eax, [ebp+bmi]
.text:5CB1FBB0 push eax ; struct tagBITMAPINFO *
.text:5CB1FBB1 mov [ebp+bmi.bmiHeader.biSize], 28h
.text:5CB1FBBB mov [ebp+bmi.bmiHeader.biWidth], ecx
.text:5CB1FBC1 mov [ebp+bmi.bmiHeader.biPlanes], 1
.text:5CB1FBCA mov [ebp+bmi.bmiHeader.biBitCount], si
.text:5CB1FBD1 mov [ebp+bmi.bmiHeader.biCompression], ebx
.text:5CB1FBD7 call ?CalcBitmapSize@ ; 如果为非OS/2且未压缩的win扩展DIB位图重新计算大小
.text:5CB1FBF4 cmp esi, 8 ; 判断biBitCount是否为1,4,8,
;因为24的不需要调色板
.text:5CB1FBF7 mov [ebp+bmi.bmiHeader.biXPelsPerMeter], ebx
.text:5CB1FBFD mov [ebp+bmi.bmiHeader.biYPelsPerMeter], ebx
.text:5CB1FC03 mov [ebp+bmi.bmiHeader.biClrUsed], eax
.text:5CB1FC09 mov [ebp+bmi.bmiHeader.biClrImportant], ebx
.text:5CB1FC0F ja loc_5CB1FC9B ; biBitCount为1,4,8不跳转
.text:5CB1FC15 mov edx, [ebp+arg_C] ; 判断参数pbmi是否指向NULL
.text:5CB1FC18 cmp edx, ebx
.text:5CB1FC1A jz short loc_5CB1FC46
.text:5CB1FC1C movzx ecx, word ptr [edx+0Eh]
.text:5CB1FC20 cmp ecx, esi ; 判断biBitCount是否一致
.text:5CB1FC22 jnz short loc_5CB1FC46
.text:5CB1FC24 mov ecx, [edx+20h]
.text:5CB1FC27 cmp ecx, ebx
.text:5CB1FC29 jnz short loc_5CB1FC2D
.text:5CB1FC2B mov ecx, eax
.text:5CB1FC2D
.text:5CB1FC2D loc_5CB1FC2D: ; !!!!!!!!!!!!!!! 问题所在 !!!!!!!!!!!!!!!!!!
.text:5CB1FC2D cmp ecx, 100h ; 判断biClrUsed是否大于0x100, 因为8bit最多256调色板
.text:5CB1FC33 jg loc_5CB1FCF0 ; 注意这里就是漏洞的根本问题,有符号比较
.text:5CB1FC39 lea esi, [edx+28h] ; 而下面是无符号的长度拷贝数值,当biClrUsed为负数,
.text:5CB1FC3C lea edi, [ebp+bmi.bmiColors] ; 满足小于0x100, 将拷贝很长的数据到esi指向的stack
.text:5CB1FC42 rep movsd ; 参数的BITMAPINFO指针向的bicolors便可以构造shellcode
.text:5CB1FC44 jmp short loc_5CB1FC9B ; biClrUsed控制shellcode长度
...... ; 下面会进行DIB Section的创建, RGB换序, bits映射到
; 内存等操作,篇幅所限先略掉了.
; 逆向后的C Code中有完整给出。
== 函数: ConvertDIBSECTIONToThumbnail (shimgvw.dll)
.text:5CB20102 mov eax, [ebx+8] ; pbmi.bmiHeader.biHeight
.text:5CB20105 cmp eax, ecx ; 判断是从顶到底,还是从底到顶来存储
.text:5CB20107 push esi
.text:5CB20108 push edi
.text:5CB20109 mov [ebp+pbmi], ebx
.text:5CB2010C mov [ebp+fTopToBottom], ecx ; fTopToBottom = FALSE
.text:5CB2010F jge short loc_5CB2011D
.text:5CB20111 neg eax ; 从顶到底,则取其补码
.text:5CB20113 mov [ebx+8], eax ; pbmi->bmiHeader.biHeight
.text:5CB20116 mov [ebp+fTopToBottom], 1
......
.text:5CB20148 mov eax, edi
.text:5CB2014A sub eax, [ebp+rect.top] ; eax = top - bottom
.text:5CB2014D cmp eax, [ebx+8] ; pbmi->bmiHeader.biHeight
.text:5CB20150 jz short loc_5CB201CA
.......
loc_5CB201CA:
.text:5CB201CA
.text:5CB201CA cmp [ebp+fTopToBottom], 1
.text:5CB201CE mov esi, [ebp+pbmi] ; esi = pbmi
.text:5CB201D1 jnz short loc_5CB201D6
.text:5CB201D3 neg dword ptr [esi+8] ; pbmi->bmiHeader.biHeight
.text:5CB201D6
.text:5CB201D6 loc_5CB201D6:
.text:5CB201D6 xor ecx, ecx ; ecx = 0
.text:5CB201D8 cmp [ebp+fOrigSize], ecx
.text:5CB201DB jz short loc_5CB20229
.text:5CB201DD movzx eax, word ptr [esi+0Eh] ; pbmi->bmiHeader.biBitCount
.text:5CB201E1 cmp eax, [ebp+dwRecClrDepth]
.text:5CB201E4 ja short loc_5CB20229
.text:5CB201E6 mov edx, [esi+4] ; pbmi->bmiHeader.biWdith
.text:5CB201E9 mov [ebp+bmiWidth], edx
.text:5CB201EC mov edx, [esi+8] ; pbmi->bmiHeader.biHeight
.text:5CB201EF mov [ebp+hMem], edx
.text:5CB201F2 lea edx, [ebp+phBmpThumbnail]
.text:5CB201F5 push edx ; int
.text:5CB201F6 push ecx ; int
.text:5CB201F7 push [ebp+phBmpThumbnail] ; int
.text:5CB201FA push esi ; pbmi
.text:5CB201FB push ecx ; ppvBits
.text:5CB201FC push eax ; eax = pbmi->bmiHeader.biBitCount
.text:5CB201FD lea eax, [ebp+bmiWidth]
.text:5CB20200 push eax ; int: pbiWidth
.text:5CB20201 call _CreateSizedDIBSECTION@28 ; <----这里就是上面分析的问题函数 !!!
.text:5CB20206 test eax, eax ; the function above cause the vul !!!!!!
.text:5CB20208 mov [ebp+pBits], eax ; fCreateDIBSECTIONResult
.text:5CB2020B jz short loc_5CB2025E
.text:5CB2020D push esi ; struct tagBITMAPINFO *
.text:5CB2020E call ?CalcBitmapSize@@YGKPBUtagBITMAPINFO@@@Z ; CalcBitmapSize(ta
== 函数: GetDocFileThumnail (shimgvw.dll)
.text:5CB0635A xor esi, esi ; esi = 0
.text:5CB0635C push esi ; hWnd
.text:5CB0635D call ds:__imp__GetDC@4 ; GetDC(x)
.text:5CB06363 push eax ; hdc
.text:5CB06364 mov [ebp+hDC], eax
.text:5CB06367 call ds:__imp__CreateCompatibleDC@4 ; 创建设备无关内存环境句柄
......
.text:5CB06377 push edi
.text:5CB06378 xor eax, eax ; eax = 0
.text:5CB0637A mov [ebp+pvarResult.vt], si
.text:5CB0637E lea edi, [ebp+pvarResult.wReserved1]
.text:5CB06381 stosd ; 初始化结构体pvarResult, 类型PROPVARIANT
.text:5CB06382 stosd
.text:5CB06383 stosd
.text:5CB06384 stosw
.text:5CB06386 mov eax, [ebp+pPropStg]
.text:5CB06389 mov edx, [eax]
.text:5CB0638B lea edi, [ebp+pvarResult] ; edi = &pvarResult
.text:5CB0638E push edi
.text:5CB0638F xor ecx, ecx
.text:5CB06391 inc ecx ; ecx = 1
.text:5CB06392 lea edi, [ebp+propSpec]
.text:5CB06395 push edi
.text:5CB06396 push ecx ; ecx = 1: PRSPEC_PROPID
.text:5CB06397 push eax ; eax = pPropStg: be added auto
.text:5CB06398 mov [ebp+ho], esi
.text:5CB0639B mov [ebp+propSpec], ecx
.text:5CB0639E mov [ebp+propSpec_propidORlpwstr], 11h
.text:5CB063A5 call dword ptr [edx+0Ch] ; 参考 IPropertyStorage C的定义得知为ReadMultiple
.text:5CB063A5 ; pPropStg->ReadMultiple(x, x, x);
.text:5CB063A8 cmp eax, esi
.text:5CB063AA mov [ebp+pPropStg], eax ; here pPropStg is the ReadMultiple return value for optimization
.text:5CB063AD jl loc_5CB06565
.text:5CB063B3 cmp [ebp+pvarResult.vt], 47h ; VT_CF
.text:5CB063B8 mov [ebp+pPropStg], 80004005h ; Error Message: E_FAIL
.text:5CB063BF jnz loc_5CB065AD
.text:5CB063C5 mov ecx, dword ptr [ebp+pvarResult.anonymous_0] ; = pvarREsult.pclipdata(since vt = VT_CF)
.text:5CB063C8 cmp dword ptr [ecx+4], -1 ; pvarResult.pclipdata->ulClipFmt:
.text:5CB063C8 ; -1 : A DWORD that contains a built-in Windows clipboard format value.
.text:5CB063CC jnz loc_5CB0
.text:5CB063D2 mov eax, [ecx+8] ; pvarResult.pclipdata->pClipData: (BYTE *)
.text:5CB063D5 lea edi, [eax+4] ; eax + 4 = ecx + 12 = pclipdata->pClipData + 4, skip 1st DWORD
.text:5CB063D8 mov eax, [eax] ; if the value of the ulClipFmt member is -1, the data is
.text:5CB063D8 ; in the form of a built-in Windows format. In this case,
.text:5CB063D8 ; the first DWORD of the buffer pointed to by pClipData is
.text:5CB063D8 ; the clipboard format identifier
.text:5CB063DA cmp eax, 3 ; 3 = CF_METAFILEPICT: metafile
.text:5CB063DD mov [ebp+pbmi], edi ; pbmi = (pvarResult.pclipdata->pClipData + sizeof(DWORD))
.text:5CB063E0 jnz loc_5CB0656F ; goto ConvertDIBSECTIONToThumbnail
.text:5CB0656F
.text:5CB0656F loc_5CB0656F: ; CF_DIB
.text:5CB0656F cmp eax, 8
.text:5CB06572 mov [ebp+pPropStg], 8004006Ah
.text:5CB06579 jnz short loc_5CB0655B
.text:5CB0657B cmp dword ptr [edi], 28h ; check if it is OS/2 DIB, or windows ext DIB
.text:5CB0657E jnz short loc_5CB0655B
.text:5CB06580 push dword ptr [ecx] ; ecx = pvarResult.pclipdata->cbsize
.text:5CB06582 push edi ; struct tagBITMAPINFO *
.text:5CB06583 call _CalcBitsOffsetInDIB@8 ; CalcBitsOffsetInDIB(x,x)
.text:5CB06588 cmp eax, esi
.text:5CB0658A jz short loc_5CB0655B
.text:5CB0658C push [ebp+fOrigSize] ; fOrigSize
.text:5CB0658F push 0Fh ; uiSharpPct
.text:5CB06591 push [ebp+hPalette] ; hPalette
.text:5CB06594 push [ebp+dwClrDepth] ; dwRecClrDepth
.text:5CB06597 push [ebp+prgSize] ; prgSize
.text:5CB0659A push [ebp+phBmpThumbnail] ; phBmpThumbnail
.text:5CB0659D push eax ; pBits
.text:5CB0659E push edi ; pbmi
.text:5CB0659F call _ConvertDIBSECTIONToThumbnail@32 ; <----这里就是了
.text:5CB065A4 test eax, eax
.text:5CB065A6 jz short loc_5CB0655B
...... ; 后面就不继续分析了
0x05 补丁分析
补丁相关文件:shimgvw.dll, shell32.dll
下面主要分析shimgvw.dll中对doc/mic问题的修补,其中改了几处,本文自分析了在DIB转Thumnail前的主要的检测函数
BOOL IsValidClipData(CLIPDATA * pClipdata)
其中的静态反汇编分析和对应的C描述,由于篇幅问题,写在了文章的(下)
链接:http://bbs.pediy.com/showthread.php?t=131300
- 标 题:微软MS11-006 Windows Shell图形处理漏洞原理及补丁分析(上)(下)
- 作 者:nineB
- 时 间:2011-03-24 15:31:30
- 链 接:http://bbs.pediy.com/showthread.php?t=131294