BUGTRAQ ID: 40725,40721 CVE ID: CVE-2010-1885 Windows是微软发布的非常流行的操作系统。 Windows中默认提供了帮助和支持中心以访问在线文档,可通过hcp://形式的URL直接访问帮助文档。在通过注册的协议处理器调用hcp:// URL时,会向帮助中心应用传送命令行参数/fromhcp,这个标记将帮助中心切换到受限制的模式,仅允许白名单中的帮助文档和参数。但这个白名单实现并不安全,可能被绕过。 在进行验证之前首先要使用MPC::HTML::UrlUnescapeW()函数规范化和转义URL,该函数使用MPC::HexToNum()将 URL转义序列翻译为原始字符。相关代码如下: .text:0106684C Unescape: .text:0106684C cmp di, '%' ; di contains the current wchar in the input URL. .text:01066850 jnz short LiteralChar ; if this is not a '%', it must be a literal character. .text:01066852 push esi ; esi contains a pointer to the current position in URL to unescape. .text:01066853 call ds:wcslen ; find the remaining length. .text:01066859 cmp word ptr [esi], 'u' ; if the next wchar is 'u', this is a unicode escape and I need 4 xdigits. .text:0106685D pop ecx ; this sequence calculates the number of wchars needed (4 or 2). .text:0106685E setz cl ; i.e. %uXXXX (four needed), or %XX (two needed). .text:01066861 mov dl, cl .text:01066863 neg dl...
BUGTRAQ ID: 40725,40721 CVE ID: CVE-2010-1885 Windows是微软发布的非常流行的操作系统。 Windows中默认提供了帮助和支持中心以访问在线文档,可通过hcp://形式的URL直接访问帮助文档。在通过注册的协议处理器调用hcp:// URL时,会向帮助中心应用传送命令行参数/fromhcp,这个标记将帮助中心切换到受限制的模式,仅允许白名单中的帮助文档和参数。但这个白名单实现并不安全,可能被绕过。 在进行验证之前首先要使用MPC::HTML::UrlUnescapeW()函数规范化和转义URL,该函数使用MPC::HexToNum()将 URL转义序列翻译为原始字符。相关代码如下: .text:0106684C Unescape: .text:0106684C cmp di, '%' ; di contains the current wchar in the input URL. .text:01066850 jnz short LiteralChar ; if this is not a '%', it must be a literal character. .text:01066852 push esi ; esi contains a pointer to the current position in URL to unescape. .text:01066853 call ds:wcslen ; find the remaining length. .text:01066859 cmp word ptr [esi], 'u' ; if the next wchar is 'u', this is a unicode escape and I need 4 xdigits. .text:0106685D pop ecx ; this sequence calculates the number of wchars needed (4 or 2). .text:0106685E setz cl ; i.e. %uXXXX (four needed), or %XX (two needed). .text:01066861 mov dl, cl .text:01066863 neg dl .text:01066865 sbb edx, edx .text:01066867 and edx, 3 .text:0106686A inc edx .text:0106686B inc edx .text:0106686C cmp eax, edx ; test if I have enough characters in input to decode. .text:0106686E jl short LiteralChar ; if not enough, this '%' is considered literal. .text:01066870 test cl, cl .text:01066872 movzx eax, word ptr [esi+2] .text:01066876 push eax .text:01066877 jz short NotUnicode .text:01066879 call HexToNum ; call MPC::HexToNum() to convert this nibble (4 bits) to an integer. .text:0106687E mov edi, eax ; edi contains the running total of the value of this escape sequence. .text:01066880 movzx eax, word ptr [esi+4] .text:01066884 push eax .text:01066885 shl edi, 4 ; shift edi left 4 positions to make room for the next digit, i.e. total <<= 4; .text:01066888 call HexToNum .text:0106688D or edi, eax ; or the next value into the 4-bit gap, i.e. total |= val. .text:0106688F movzx eax, word ptr [esi+6]; this process continues for the remaining wchars. .text:01066893 push eax .text:01066894 shl edi, 4 .text:01066897 call HexToNum .text:0106689C or edi, eax .text:0106689E movzx eax, word ptr [esi+8] .text:010668A2 push eax .text:010668A3 shl edi, 4 .text:010668A6 call HexToNum .text:010668AB or edi, eax .text:010668AD add esi, 0Ah ; account for number of bytes (not chars) consumed by the escape. .text:010668B0 jmp short FinishedEscape .text:010668B2 .text:010668B2 NotUnicode: .text:010668B2 call HexToNum ; this is the same code, but for non-unicode sequences (e.g. %41, instead of %u0041) .text:010668B7 mov edi, eax .text:010668B9 movzx eax, word ptr [esi] .text:010668BC push eax .text:010668BD call HexToNum .text:010668C2 shl eax, 4 .text:010668C5 or edi, eax .text:010668C7 add esi, 4 ; account for number of bytes (not chars) consumed by the escape. .text:010668CA .text:010668CA FinishedEscape: .text:010668CA test di, di .text:010668CD jz short loc_10668DA .text:010668CF .text:010668CF LiteralChar: .text:010668CF push edi ; append the final value to the normalised string using a std::string append. .text:010668D0 mov ecx, [ebp+unescaped] .text:010668D3 push 1 .text:010668D5 call std::string::append .text:010668DA mov di, [esi] ; fetch the next input character. .text:010668DD test di, di ; have we reached the NUL terminator? .text:010668E0 jnz Unescape ; process next char. MPC::HexToNum()处理出错情况的方式存在错误,相关代码如下: .text:0102D32A mov edi, edi .text:0102D32C push ebp .text:0102D32D mov ebp, esp ; function prologue. .text:0102D32F mov eax, [ebp+arg_0] ; fetch the character to convert. .text:0102D332 cmp eax, '0' .text:0102D335 jl short CheckUppercase ; is it a digit? .text:0102D337 cmp eax, '9' .text:0102D33A jg short CheckUppercase .text:0102D33C add eax, 0FFFFFFD0h ; atoi(), probably written val - '0' and optimised by compiler. .text:0102D33F jmp short Complete .text:0102D341 CheckUppercase: .text:0102D341 cmp eax, 'A' .text:0102D344 jl short CheckLowercase ; is it an uppercase xdigit? .text:0102D346 cmp eax, 'F' .text:0102D349 jg short CheckLowercase .text:0102D34B add eax, 0FFFFFFC9h ; atoi() .text:0102D34E jmp short Complete .text:0102D350 CheckLowercase: .text:0102D350 cmp eax, 'a' .text:0102D353 jl short Invalid ; lowercase xdigit? .text:0102D355 cmp eax, 'f' .text:0102D358 jg short Invalid .text:0102D35A add eax, 0FFFFFFA9h ; atoi() .text:0102D35D jmp short Complete .text:0102D35F Invalid: .text:0102D35F or eax, 0FFFFFFFFh ; invalid character, return -1 .text:0102D362 Complete: .text:0102D362 pop ebp .text:0102D363 retn 4 MPC::HTML::UrlUnescapeW()没有按照需求检查MPC::HexToNum()的返回代码,因此可能向std::strings附加内容,之后可以利用代码中的计算错误绕过/fromhcp白名单。 攻击者可以通过使用特制的hcp:// URL打开sysinfomain.htm帮助文档时的输入验证错误来利用这个漏洞执行任意命令。 Microsoft Windows XP SP3 Microsoft Windows XP SP2 Microsoft Windows Server 2003 SP2 临时解决方法: * 暂时去除HCP协议的注册 在命令窗口中执行: reg export HKEY_CLASSES_ROOT\HCP hcp_backup.reg 备份注册表中相关的表项到备份文件。 然后执行: reg delete HKEY_CLASSES_ROOT\HCP /f 删除相关的注册表项去除系统的HCP协议注册。在微软发布的相关漏洞补丁安装以后,双击备份出来的hcp_backup.reg文件导入数据到注册表后即可恢复对HCP的支持。 厂商补丁: Microsoft --------- 目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本: http://www.microsoft.com/technet/security/