首页
社区
课程
招聘
[原创]微软 MS11-015 Windows Media 中处理 dvr-ms 格式文件漏洞分析
发表于: 2011-4-1 01:45 7665

[原创]微软 MS11-015 Windows Media 中处理 dvr-ms 格式文件漏洞分析

2011-4-1 01:45
7665

作者: nine8
QQ  : 279933462
杂记: http://hi.baidu.com/tapeout

MS11-015微软补了Media Player的2个漏洞,其中库预加载的可以导致远程执行代码,但是第二个感觉只是导致后面解码时的错误不会导致远程执行代码:

     1). DLL库预加载的, 通过构造相关的dll文件,涉及到dvr-ms, mpg和mtv文件类型的打开时可能会加载,导致远程执行代码。

     2). Media Player在播放dvr-ms文件时,会调用Stream Buffer Engine来处理dvr-ms文件流, 在处理的时候sbe.dll中的问题导致可能存在的处理错误,但是个人分析感觉不能
          被利用远程执行代码。(另外也可能是我分析的错误,或是出现问题的地方定位就不对)。

由于没有POC,以及对触发问题的dvr-ms文件格式不熟悉,相关东西都是现看的,所以分析中可能会有很多问题,如果大家发现,还请给小弟多多指出,感谢!

下面对MS11-015的DVR-MS 漏洞 CVE-2011-0042, 做简要的分析。对于CVE-2011-0032,由于不涉及WinXP, VM里跑vista或win7很不顺畅,这里就先没有分析.

  0x01  相关概要
--------------------------

      == 0x11  调试环境:  VMware7.0 + en_windows_xp_professional_with_service_pack_3_x86

      == 0x12  漏洞编号:  MS11-015, CVE-2011-0042

      == 0x13  问题文件:  c:\windows\system32\sbe.dll

      == 0x14  名词摘要: (摘录自微软MSDN)
           
                        1) . 流缓冲引擎 (SBE)。利用 SBE,应用程序可以搜索、暂停以及录制实时视频流,而不会中断该流。实时内容和录制内容之间的转换为无缝转换。现在,
                             SBE 支持 MPEG-2 视频和数字视频 (DV) 源,捕获速率高达每秒 30 兆比特 (Mbps)。

                         2).  在 Microsoft Windows XP Media Center Edition 中,Microsoft 已引入了 *.dvr-ms 文件格式。类似于 *.asf 格式,*.dvr-ms 文件增强了允
                             许创建关键PVR 的功能,其中包括时光平移、实时暂停以及同时录制和播放。

  0x02  问题分析
---------------------------

.text:4EE52F2F public: static long __stdcall DShowWMSDKHelpers::RecoverNewMediaType(struct INSSBuffer3 *, struct _AMMediaType * *) proc near
.text:4EE52F2F
.text:4EE52F2F var_4= dword ptr -4
.text:4EE52F2F pINSSBuffer3= dword ptr  8                                   ; 第一个参数指向INSSBuffer3
.text:4EE52F2F ppAMMediaType= dword ptr  0Ch                          ; 第二个参数指向AMMediaType指针
.text:4EE52F2F
.text:4EE52F2F   mov   edi, edi
.text:4EE52F31   push  ebp
.text:4EE52F32   mov   ebp, esp
.text:4EE52F34   push  ecx
.text:4EE52F35   push  ebx
.text:4EE52F36   push  esi
.text:4EE52F37   mov   ebx, [ebp+pINSSBuffer3]
.text:4EE52F3A   push  edi
.text:4EE52F3B   mov   eax, [ebx]
.text:4EE52F3D   lea   ecx, [ebp+var_4]
.text:4EE52F40   push  ecx                                                              ; Buffer大小
.text:4EE52F41   push  0                                                                 ; 将接收属性内容的Buffer指向NULL, 获取所需大小空间
.text:4EE52F43   sub   esp, 10h
.text:4EE52F46   mov   edi, esp
.text:4EE52F48   mov   esi, offset _INSSBuffer3Prop_DShowNewMediaType    : 这里是下面要获取的属性GUID
.text:4EE52F4D   movsd                                                                 ; DShowNewMediaType
.text:4EE52F4E   movsd                                                                  :1135BEB7-3A39-47BA-D998-69Eb006BC715
.text:4EE52F4F   movsd
.text:4EE52F50   push  ebx                                                            ; INSSBuffer3 *
.text:4EE52F51   movsd
.text:4EE52F52   call  dword ptr [eax+2Ch]            ; 通过INSSBuffer3的GetProperty获取DShowNewMediaType属性内容
.text:4EE52F55   mov   esi, eax                               ; 这里也是通过逆向分析才推出是调用的GetProperty,之前并不知道功能。
.text:4EE52F57   test  esi, esi
.text:4EE52F59   jl    loc_4EE5300F

HRESULT ( STDMETHODCALLTYPE *GetProperty )( 
            INSSBuffer3 * This,
            /* [in] */ GUID guidBufferProperty,
            /* [out] */ void *pvBufferProperty,
            /* [out][in] */ DWORD *pdwBufferPropertySize);
.text:4EE52F5F   push  [ebp+var_4]                                      ; 这里为通过上面获取的所需存储GUID内容的空间大小
.text:4EE52F62   call  operator new(uint)                                         ; 开辟内存空间, 之后出现问题的地方会涉及到这片空间内容 !!!
.text:4EE52F67   test  eax, eax
.text:4EE52F69   pop   ecx
.text:4EE52F6A   mov   [ebp+pINSSBuffer3], eax                                                         
.text:4EE52F6D   jz    loc_4EE5300
.text:4EE52F73   mov   ecx, [ebx]
.text:4EE52F75   lea   edx, [ebp+var_4]
.text:4EE52F78   push  edx                                                                ; 所需接收空间大小,单位byte
.text:4EE52F79   push  eax                                                                ; 接收buffer指向上面开辟的空间
.text:4EE52F7A   sub   esp, 10h
.text:4EE52F7D   mov   edi, esp
.text:4EE52F7F   mov   esi, offset _INSSBuffer3Prop_DShowNewMediaType      ; GUID
.text:4EE52F84   movsd
.text:4EE52F85   movsd
.text:4EE52F86   movsd
.text:4EE52F87   push  ebx
.text:4EE52F88   movsd
.text:4EE52F89   call  dword ptr [ecx+2Ch]                                         ; NSSBuffer3 GetProperty
.text:4EE52F8C   mov   esi, eax
.text:4EE52F8E   test  esi, esi
.text:4EE52F90   jl    short loc_4EE52FFF

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (2)
雪    币: 19
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
下面是INSSBuffer3 GetProperty的实现

.text:7D814231
.text:7D814231 loc_7D814231:
.text:7D814231 mov     edx, [ebx]
.text:7D814233 push    ebx                                     ;
.text:7D814234 call    dword ptr [edx+3Ch] ;         // 这里会调用函数sub_7D8143C0
.text:7D814237 mov     esi, eax                              // 传入INSSBuffer3*, GUID, Buf,
.text:7D814239 test    esi, esi                                 // 和BufSize4个参数
.text:7D81423B jge     short loc_7D814284


下面的函数主要是先判断是否为一个GUID属性,如果不是则进行查找。

.text:7D8143C0 sub_7D8143C0 proc near
.text:7D8143C0
.text:7D8143C0 p_arg2= dword ptr -18h
.text:7D8143C0 p_GUID= byte ptr -14h
.text:7D8143C0 SecCookie= dword ptr -4
.text:7D8143C0 arg_0= dword ptr  8
.text:7D8143C0 arg_1= byte ptr  0Ch
.text:7D8143C0 arg_2= dword ptr  1Ch
.text:7D8143C0 arg_3= dword ptr  20h
.text:7D8143C0
.text:7D8143C0 mov     edi, edi
.text:7D8143C2 push    ebp
.text:7D8143C3 mov     ebp, esp
.text:7D8143C5 sub     esp, 18h
.text:7D8143C8 mov     ecx, [ebp+arg_2] ; ecx = arg2
.text:7D8143CB mov     eax, dword_7D933080
.text:7D8143D0 mov     edx, [ebp+arg_3] ; edx = arg_3
.text:7D8143D3 push    ebx
.text:7D8143D4 push    esi
.text:7D8143D5 push    edi
.text:7D8143D6 lea     esi, [ebp+arg_1]
.text:7D8143D9 lea     edi, [ebp+p_GUID]
.text:7D8143DC movsd
.text:7D8143DD movsd
.text:7D8143DE movsd
.text:7D8143DF movsd
.text:7D8143E0 mov     [ebp+p_arg2], ecx ; var_18 = ecx = arg_2
.text:7D8143E3 push    4
.text:7D8143E5 pop     ecx             ; ecx = 4
.text:7D8143E6 lea     edi, [ebp+p_GUID]
.text:7D8143E9 mov     esi, offset dword_7D87F750    ; 这里是另一个GUID值
.text:7D8143EE xor     ebx, ebx        ; ebx = 0
.text:7D8143F0 repe cmpsd
.text:7D8143F2 mov     [ebp+SecCookie], eax
.text:7D8143F5 mov     eax, [ebp+arg_0] ; eax = arg0
.text:7D8143F8 jnz     short loc_7D81442D      ; 如果不是调用函数查找


下面函数传入4个参数,其中第一个参数应该是指向链表结构,offset相对于INSSBuffer3为0x3c
剩下的3个参数为GUID, Buf, BufSize

.text:7D81442D
.text:7D81442D loc_7D81442D:           ; arg3
.text:7D81442D push    edx
.text:7D81442E push    [ebp+p_arg2]    ; var_18 = arg2
.text:7D814431 lea     esi, [ebp+p_GUID]
.text:7D814434 sub     esp, 10h
.text:7D814437 mov     edi, esp
.text:7D814439 movsd
.text:7D81443A movsd
.text:7D81443B movsd
.text:7D81443C lea     ecx, [eax+3Ch]  ; ecx = arg0+0x3c
.text:7D81443F movsd
.text:7D814440 call    sub_7D815170


下面是sub_7D815170, 主要是查找通过遍历链表结构成员查找GUID属性,如果找到GUID则获
取其后面的AMMediaType数据信息

.text:7D8151A5
.text:7D8151A5 loc_7D8151A5:
.text:7D8151A5 push    [ebp+var_18]
.text:7D8151A8 mov     ecx, ebx        ; ecx = ebx = arg0
.text:7D8151AA call    sub_7D814F74                     ;   遍历查找GUID
.text:7D8151AF push    4
.text:7D8151B1 pop     ecx             ; ecx = 4
.text:7D8151B2 lea     edi, [ebp+dwBufForID]
.text:7D8151B5 mov     esi, eax
.text:7D8151B7 xor     edx, edx        ; edx = 0
.text:7D8151B9 repe cmpsd
.text:7D8151BB jz      short loc_7D8151E6


.text:7D8151EA push    [ebp+p_arg3]
.text:7D8151ED mov     ecx, ebx        ; ecx = ebx = arg0
.text:7D8151EF push    [ebp+p_arg2]
.text:7D8151F2 push    0
.text:7D8151F4 push    [ebp+var_18]
.text:7D8151F7 call    sub_7D8150DB    ; 如果找到GUID属性,获取其数据内容
.text:7D8151FC jmp     short loc_7D8151D7
.text:7D8151FC sub_7D815170 endp


下面就不详细写了,其中一个是当输入的参数指向NULL的时候,会返回BufSize为GUID后面的第
一个QWORD Size里的值,然后返回0.

另外2个是根据IndexVector来在链表结构中查找对应的GUID属性内容,下面是我简单的推测的
结构。可能不准或不对。有些是中间的推导过程记录的,后面可能变了,但没改过去。

sub_7D814E60:

+-------------------------------------+                <--- arg0
|           DWORD                         |
+-------------------------------------+                <--- arg + 0x04: 标记该元素单元的地址范围
|node offset addr refr link head|                                       
+-------------------------------------+                <--- arg0 + 0x08
|                                          | bit0 |
+-------------------------------------+                <--- arg0 + 0x0c
| ID Address ( if +0x8 bit0=1 )         |
+-------+---------+--------+--------+                <--- arg0 + 0x10
|            | b7-b4  | b7-b0 | b7-b0 |                                                                       
+-------+---------+--------+----------+                <--- arg0 + 0x14
|                        .........                     |
|                                                     |
| 如果从 arg0+0x10, 0x11, 0x12中 |
|的bit Flag检索值为1,则:                     |
| arg0+0x14+arg1*4 指向的DW存 |<--- 如果从Flag的bit中检索值为1,则ID的地址从这个范
|有ID的Address.                             |
|  Bit Flag为1的优先级大于offset      |
|bit0为1的优先级.                             |                               
|                        .........                     |
+----------------------------------------+                <--- arg0 + 0x64
|        next node start address             |
+----------------------------------------+                <--- arg0 + 0x68
|prev node end offset value addr |               
+----------------------------------------+

其中:
arg0+0x10的 bit7 到 bit0: 分别对应地址 arg0+0x14 到 arg0+0x33        (8个DWORD)
arg0+0x11的 bit7 到 bit0: 分别对应地址 arg0+0x34 到 arg0+0x53        (8个DWORD)
arg0+0x12的 bit7 到 bit4: 分别对应地址 arg0+0x54 到 arg0+0x63        (4个DWORD)

sub_7D814DBE:

// 函数: sub_7D814DBE(BaseAddr, BitOffset);
//
// 功能: 根据参数arg1指定的offset和bit Mask,来返回对应的Bit值是1还是0
//
//                +-------------------------------+                <--- arg0
//                |                          DWORD                                |
//                +-------------------------------+                <---- arg + 0x04
//                |                          DWORD                                |                       
//                +-------------------------------+                <--- arg0 + 0x08
//                |                          DWORD                                |
//                +-------------------------------+                <--- arg0 + 0x0c
//                |                          DWORD                                |
//                +-------+-------+-------+-------+                <--- arg0 + 0x10
//                |                | Flags | Flags        | Flags        |                                                                                        |
//                +-------+-------+-------+-------+
//
//               
//                real pointer = arg0 + 0x16 + offset(Byte Offset, Bit Offset)
//
//
//                DWORD arg1 format: (用于指定offset的, Byte offset和bit offset)
//
//                +------------------------------------+-----------------------------------+               
//                | byte offset of checked byte number | bit offset of checked byte number |
//                +------------------------------------+-----------------------------------+
//                bit31                        -----                                bit4                        ------                                bit0
//
//                == Bit31 - Bit4 : (byte offset of checked number)
//                       
//                        指定要被测试的Bit所在Byte的地址偏移量
//                               
//                       
//                == Bit3 - Bit0 : (bit offset of checked number)
//                       
//                        指明要被测试的Bit的Byte偏移基础上的bit偏移量
//
//                        0 - check byte bit-7 value
//                        1 - check byte bit-6 value
//                        2 - check byte bit-5 value       
//                        3 - check byte bit-4 value
//                        4 - check byte bit-3 value
//                        5 - check byte bit-2 value
//                        6 - check byte bit-1 value
//                        7 - check byte bit-0 value
//
//                所以被测试的Bit的偏移过程:
//                        通过Byte Offset确定其所在byte的地址, 然后同过bit offset定位到具体的是哪个bit
//
//
// 返回: 如果对应的bit为1, 则返回1; 为0, 则返回0;
//                 也就是返回对应bit的值.
//

BYTE BitMask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};

// ChkBitValue
sub_7D814DBE(
	arg0,		// Base Addr
	arg1)		// BitOffset
{
	BYTE BitMaskIndex;
	BYTE ByteNum;
	BYTE BitFlag;

	ByteNum = (*( arg0 + 0x10 + (arg1 >> 3) )) & 0x7;

	BitMaskIndex = arg1 & 0x7;

	BitFlag = ByteNum & BitMask[BitMaskIndex];

	return( (BitFlag == 0) ? 0 : 1 );	
}
2011-4-1 01:47
0
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
3
漏洞分析神马的,看起来就是晕,只有亲自动手调试过之后才能真正看明白啊~~~~~~
2011-4-3 22:46
0
游客
登录 | 注册 方可回帖
返回
//