目录
MS10-013
Microsoft DirectShow 中的漏洞可能允许远程执行代码 (977935)
摘要
此安全更新解决 Microsoft DirectShow 中一个安全报告的漏洞。 如果用户打开特制 AVI 文件,这两个漏洞可能允许远程执行代码。 成功利用此漏洞的攻击者可以完全控制受影响的系统。 攻击者可随后安装程序;查看、更改或删除数据;或者创建拥有完全用户权限的新帐户。 那些帐户被配置为拥有较少系统用户权限的用户比具有管理用户权限的用户受到的影响要小。
补丁分析
我们这里以windows 7的x86的补丁分析,补丁解开之后的目录列表如下:
重点查看补丁文件为:
- directshow-core_6.1.7600.16490\
- 2009/12/19 17:02 1,328,640 quartz.dll
- video-for-windows_6.1.7600.16490\
- 2009/07/14 09:14 65,024 avicap32.dll
- 2009/12/19 17:02 91,648 avifil32.dll
- 2009/12/19 17:02 84,480 mciavi32.dll
- 2009/12/19 17:02 13,312 msrle32.dll
- 2009/07/14 09:15 120,320 msvfw32.dll
- 2009/12/19 17:02 31,744 msvidc32.dll
quartz.dll
主要包括三个更新函数:
- CheckVideoType
- CAviMSROutPin::ParseHeader
- CAviMSRFilter::ParseHeaderCreatePins
CheckVideoType
更新前
unsigned int __thiscall CColour::CheckVideoType(CColour *this, const struct _AMMediaType *a2)
{
unsigned int result; // eax
if ( !memcmp(a2, &MEDIATYPE_Video, 0x10u) && !memcmp(&a2->formattype, &FORMAT_VideoInfo, 0x10u) )
result = a2->cbFormat < 0x58 ? 0x8004022A : 0;
else
result = -2147220950;
return result;
}
更新后
int __thiscall CColour::CheckVideoType(CColour *this, const struct _AMMediaType *a2)
{
int result; // eax
ULONG v3; // ecx
if ( !memcmp(a2, &MEDIATYPE_Video, 0x10u)
&& !memcmp(&a2->formattype, &FORMAT_VideoInfo, 0x10u)
&& (v3 = a2->cbFormat, v3 >= 0x58) )
{
result = ValidateBitmapInfoHeader((int *)a2->pbFormat + 12, v3 - 48) ? 0 : -2147220950;
}
else
{
result = -2147220950;
}
return result;
}
CAviMSROutPin::ParseHeader
更新前
int __thiscall CAviMSROutPin::ParseHeader(CAviMSROutPin *this, struct _rifflist *a2, unsigned int a3)
{
......
CAviMSROutPin::BuildMT(this);
......
}
更新后
int __thiscall CAviMSROutPin::ParseHeader(CAviMSROutPin *this, struct _rifflist *a2, unsigned int a3)
{
......
if ( CAviMSROutPin::BuildMT(this) < 0
&& *(_DWORD *)(*((_DWORD *)this + 84) + 8) == 1935960438
&& !ValidateBitmapInfoHeader((int *)(*((_DWORD *)this + 85) + 8), *(_DWORD *)(*((_DWORD *)this + 85) + 4)) )
{
return 0;
}
......
}
CAviMSRFilter::ParseHeaderCreatePins
更新前
int __thiscall CAviMSRFilter::ParseHeaderCreatePins(CAviMSRFilter *this)
{
int v2; // ebx
struct _riffchunk *v3; // edi
unsigned __int8 *v4; // ebx
int result; // eax
FOURCC v6; // eax
int v7; // eax
bool v8; // al
struct _rifflist *v9; // edi
unsigned int v10; // eax
int v11; // [esp-4h] [ebp-18h]
struct _riffchunk *v12; // [esp+Ch] [ebp-8h] BYREF
v2 = *((_DWORD *)this + 45);
*((_DWORD *)this + 46) = 0;
v3 = (struct _riffchunk *)*((_DWORD *)this + 44);
v4 = (unsigned __int8 *)v3 + v2;
v12 = v3;
if ( !IsValidRIFFChunk(v3, v4) )
return -2147220945;
while ( 1 )
{
if ( v3->fcc == 1414744396 )
{
if ( v3->cb >= 0xC )
{
v6 = v3[1].fcc;
if ( v6 == 1819440243 )
{
++*((_DWORD *)this + 31);
}
else if ( v6 == 1819108463 )
{
*((_DWORD *)this + 47) = v3;
}
}
}
else if ( v3->fcc == 1751742049 && v3->cb >= 0x28 )
{
*((_DWORD *)this + 46) = v3;
}
if ( *((_DWORD *)this + 31) >= 0x80u )
goto LABEL_16;
result = GetNextRIFFChunk(v3, v4, &v12);
if ( result < 0 )
goto LABEL_17;
if ( result )
break;
v3 = v12;
}
v7 = *((_DWORD *)this + 46);
if ( !v7 )
{
LABEL_16:
result = -2147220945;
LABEL_17:
*((_DWORD *)this + 31) = 0;
return result;
}
v8 = *((_DWORD *)this + 31) == 2 && (*(_DWORD *)(v7 + 20) & 0x100) != 0;
*((_BYTE *)this + 205) = v8;
result = CAviMSRFilter::CreatePins(this);
if ( result < 0 )
return result;
v9 = (struct _rifflist *)*((_DWORD *)this + 44);
v10 = 0;
v12 = 0;
while ( v9 < (struct _rifflist *)v4 )
{
if ( v9->fcc == 1414744396 && v9->fccListType == 1819440243 )
{
if ( v10 >= *((_DWORD *)this + 31) )
return -2147220945;
if ( CAviMSROutPin::ParseHeader(*(CAviMSROutPin **)(*((_DWORD *)this + 30) + 4 * v10), v9, v10) )
{
v12 = (struct _riffchunk *)((char *)v12 + 1);
}
else
{
--*((_DWORD *)this + 31);
v11 = *(_DWORD *)(*((_DWORD *)this + 30) + 4 * *((_DWORD *)this + 31)) + 12;
(*(void (__stdcall **)(int))(*(_DWORD *)v11 + 8))(v11);
*(_DWORD *)(*((_DWORD *)this + 30) + 4 * *((_DWORD *)this + 31)) = 0;
}
v10 = (unsigned int)v12;
}
v9 = (struct _rifflist *)((char *)v9 + v9->cb + (v9->cb & 1) + 8);
}
*((_DWORD *)this + 31) = v10;
return v10 != 0 ? 0 : -2147220945;
}
更新后
int __thiscall CAviMSRFilter::ParseHeaderCreatePins(CAviMSRFilter *this)
{
struct _riffchunk *v2; // ebx
int v3; // edi
unsigned __int8 *v4; // edi
int result; // eax
FOURCC v6; // eax
int v7; // eax
bool v8; // al
struct _rifflist *v9; // edi
unsigned int v10; // ebx
int v11; // eax
unsigned int v12; // edx
_DWORD *v13; // eax
int v14; // ecx
struct _riffchunk *v15; // ebx
int v16; // eax
unsigned __int8 *v17; // [esp+Ch] [ebp-10h]
unsigned int v18; // [esp+10h] [ebp-Ch]
struct _riffchunk *v19; // [esp+14h] [ebp-8h] BYREF
v2 = (struct _riffchunk *)*((_DWORD *)this + 44);
v3 = *((_DWORD *)this + 45);
*((_DWORD *)this + 46) = 0;
v4 = (unsigned __int8 *)v2 + v3;
v19 = v2;
v17 = v4;
if ( !IsValidRIFFChunk(v2, v4) )
return -2147220945;
while ( 1 )
{
if ( v2->fcc == 1414744396 )
{
if ( v2->cb >= 0xC )
{
v6 = v2[1].fcc;
if ( v6 == 1819440243 )
{
++*((_DWORD *)this + 31);
}
else if ( v6 == 1819108463 )
{
*((_DWORD *)this + 47) = v2;
}
}
}
else if ( v2->fcc == 1751742049 && v2->cb >= 0x28 )
{
*((_DWORD *)this + 46) = v2;
}
if ( *((_DWORD *)this + 31) >= 0x80u )
goto LABEL_16;
result = GetNextRIFFChunk(v2, v4, &v19);
if ( result < 0 )
goto LABEL_17;
if ( result )
break;
v2 = v19;
}
v7 = *((_DWORD *)this + 46);
if ( !v7 )
{
LABEL_16:
result = -2147220945;
LABEL_17:
*((_DWORD *)this + 31) = 0;
return result;
}
v8 = *((_DWORD *)this + 31) == 2 && (*(_DWORD *)(v7 + 20) & 0x100) != 0;
*((_BYTE *)this + 205) = v8;
result = CAviMSRFilter::CreatePins(this);
if ( result < 0 )
return result;
v9 = (struct _rifflist *)*((_DWORD *)this + 44);
v10 = 0;
v18 = 0;
while ( v9 < (struct _rifflist *)v17 )
{
if ( v9->fcc == 1414744396 && v9->fccListType == 1819440243 )
{
if ( v10 >= *((_DWORD *)this + 31) )
return -2147220945;
if ( CAviMSROutPin::ParseHeader(*(CAviMSROutPin **)(*((_DWORD *)this + 30) + 4 * v10), v9, v10) )
{
v18 = ++v10;
}
else
{
--*((_DWORD *)this + 31);
v11 = *(_DWORD *)(*((_DWORD *)this + 30) + 4 * v10);
v19 = *(struct _riffchunk **)(v11 + 280);
(*(void (__stdcall **)(int))(*(_DWORD *)(v11 + 12) + 8))(v11 + 12);
v12 = v10;
if ( v10 < *((_DWORD *)this + 31) )
{
do
{
v13 = (_DWORD *)(*((_DWORD *)this + 30) + 4 * v12);
v14 = v13[1];
v15 = *(struct _riffchunk **)(v14 + 280);
*v13 = v14;
v16 = *(_DWORD *)(*((_DWORD *)this + 30) + 4 * v12++);
*(_DWORD *)(v16 + 280) = v19;
v19 = v15;
}
while ( v12 < *((_DWORD *)this + 31) );
v10 = v18;
}
*(_DWORD *)(*((_DWORD *)this + 30) + 4 * *((_DWORD *)this + 31)) = 0;
}
}
v9 = (struct _rifflist *)((char *)v9 + v9->cb + (v9->cb & 1) + 8);
}
*((_DWORD *)this + 31) = v10;
return v10 != 0 ? 0 : -2147220945;
}
msrle32.dll
主要包括二个更新函数:
- RleDecompressQuery
- RleDecompressGetFormat
RleDecompressQuery
更新前
int __stdcall RleDecompressQuery(int a1, int a2, int a3)
{
__int16 v3; // dx
int v4; // ecx
int result; // eax
if ( a2
&& ((v3 = *(_WORD *)(a2 + 14), v3 == 8) || *(_DWORD *)(a2 + 16) != 1)
&& ((v4 = *(_DWORD *)(a2 + 16)) == 0 || v4 == 1)
&& (!a3
|| !*(_DWORD *)(a3 + 16)
&& *(_WORD *)(a3 + 14) == v3
&& *(_DWORD *)(a3 + 4) == *(_DWORD *)(a2 + 4)
&& *(_DWORD *)(a3 + 8) == *(_DWORD *)(a2 + 8)) )
{
result = 0;
}
else
{
result = -2;
}
return result;
}
更新后
int __stdcall RleDecompressQuery(int a1, int a2, int a3)
{
__int16 v3; // cx
int v4; // eax
int result; // eax
if ( a2
&& ValidateBitmapInfoHeader((int *)a2, 0x90Cu)
&& ((v3 = *(_WORD *)(a2 + 14), v3 == 8) || *(_DWORD *)(a2 + 16) != 1)
&& ((v4 = *(_DWORD *)(a2 + 16)) == 0 || v4 == 1)
&& (!a3
|| !*(_DWORD *)(a3 + 16)
&& *(_WORD *)(a3 + 14) == v3
&& *(_DWORD *)(a3 + 4) == *(_DWORD *)(a2 + 4)
&& *(_DWORD *)(a3 + 8) == *(_DWORD *)(a2 + 8)) )
{
result = 0;
}
else
{
result = -2;
}
return result;
}
RleDecompressGetFormat
更新前
int __stdcall RleDecompressGetFormat(int a1, int a2, ULONG pulResult)
{
int result; // eax
int v4; // eax
__int16 v5; // ax
result = RleDecompressQuery(a1, a2, 0);
if ( result )
return result;
v4 = *(_DWORD *)(a2 + 32);
if ( !v4 && *(_WORD *)(a2 + 14) == 8 )
v4 = 256;
if ( !pulResult )
return 4 * v4 + 40;
qmemcpy((void *)pulResult, (const void *)a2, 0x28u);
memcpy((void *)(pulResult + 40), (const void *)(a2 + *(_DWORD *)a2), 4 * v4);
*(_DWORD *)pulResult = 40;
v5 = *(_WORD *)(a2 + 14);
*(_DWORD *)(pulResult + 16) = 0;
*(_WORD *)(pulResult + 14) = v5;
if ( SAFE_DIBSIZE(pulResult, pulResult + 20) >= 0 )
result = 0;
else
result = -7;
return result;
}
更新后
int __stdcall RleDecompressGetFormat(int a1, int a2, ULONG pulResult)
{
int result; // eax
unsigned int v4; // eax
__int16 v5; // ax
result = RleDecompressQuery(a1, a2, 0);
if ( result )
return result;
v4 = *(_DWORD *)(a2 + 32);
if ( !v4 )
{
if ( *(_WORD *)(a2 + 14) != 8 )
{
LABEL_6:
if ( *(_DWORD *)a2 < 0x28u )
return -2;
if ( !pulResult )
return 4 * v4 + 40;
qmemcpy((void *)pulResult, (const void *)a2, 0x28u);
memcpy((void *)(pulResult + 40), (const void *)(a2 + *(_DWORD *)a2), 4 * v4);
*(_DWORD *)pulResult = 40;
v5 = *(_WORD *)(a2 + 14);
*(_DWORD *)(pulResult + 16) = 0;
*(_WORD *)(pulResult + 14) = v5;
if ( SAFE_DIBSIZE(pulResult, pulResult + 20) >= 0 )
return 0;
return -7;
}
v4 = 256;
}
if ( v4 > 0x100 )
return -2;
goto LABEL_6;
}
重点分析
- 在多个函数中增加了文件header的验证函数ValidateBitmapInfoHeader
- 最后的利用点在函数RleDecompressGetFormat中的如下片段
v4 = *(_DWORD *)(a2 + 32);
......
memcpy((void *)(pulResult + 40), (const void *)(a2 + *(_DWORD *)a2), 4 * v4);
网上没找到相应的分析记录,这里把分析过程和结果记录一下,以方便大家的学习。