首页
论坛
课程
招聘
[原创]OGAEXEC.exe对GetSecurityDescriptorDacl函数的调用结果理解错误导致拒绝服务
2009-10-8 20:48 4831

[原创]OGAEXEC.exe对GetSecurityDescriptorDacl函数的调用结果理解错误导致拒绝服务

2009-10-8 20:48
4831
摘要:新版Office正版增值计划通知程序组件OGAEXEC.exe在读取odataext.dat文件的安全描述符及其中的DACL内容的过程中,在调用GetSecurityDescriptorDacl后的判断中,忽略了lpbDaclPresent为TRUE而pDacl为NULL的情况,导致直接使用NULL的pDacl指针调用GetAclInformation,从而触发了一个access violation(0xC0000005),导致程序出错退出。

国庆回来,打开电脑,Windows Update更新了OGA通知(KB949810)的一个新版本。
更新完后重启电脑,登录进入桌面时OGAEXEC.exe进程出现错误提示,0x7c94cede处访问的0x00000000内存不能为Read。

网上搜索一下,发现这个问题八月底就有人在微软论坛反映了:
http://social.microsoft.com/Forums/en-US/genuineoffice/thread/3448c562-7799-45ec-ac41-a3fd4c36c45b
用户向微软反馈后,微软提供的方法是要求用户取消任务计划中的OGALogon.job,相当于取消这个验证功能来避免这个提示。这说明确实是OGA程序自己的问题。

为了看到问题在哪里,我再次重启电脑,当错误提示出现时点“取消”,激活了作为JIT调试器的WINDBG:

(bc0.7f0): Access violation - code c0000005 (!!! second chance !!!)
eax=0006fe58 ebx=0000ffff ecx=0006fe64 edx=0006fe80 esi=00000000 edi=80070000
eip=7c94cede esp=0006fe18 ebp=0006fe1c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!RtlQueryInformationAcl+0x9:
7c94cede 8a06            mov     al,byte ptr [esi]          ds:0023:00000000=??

0:000> u ntdll!RtlQueryInformationAcl
ntdll!RtlQueryInformationAcl:
7c94ced5 8bff            mov     edi,edi
7c94ced7 55              push    ebp
7c94ced8 8bec            mov     ebp,esp
7c94ceda 56              push    esi
7c94cedb 8b7508          mov     esi,dword ptr [ebp+8]
7c94cede 8a06            mov     al,byte ptr [esi]
7c94cee0 3c02            cmp     al,2
7c94cee2 7256            jb      ntdll!RtlQueryInformationAcl+0x7d (7c94cf3a)

这个Access Violation是在ntdll!RtlQueryInformationAcl中触发的,原因是这时传入的pAcl参数为NULL。

0:000> kb
ChildEBP RetAddr  Args to Child              
0006fe1c 77dc7e8f 00000000 0006fe58 0000000c ntdll!RtlQueryInformationAcl+0x9
*** ERROR: Module load completed but symbols could not be loaded for C:\WINDOWS\system32\OGAEXEC.exe
WARNING: Stack unwind information not available. Following frames may be wrong.
0006fe34 01004b5a 00000000 0006fe58 0000000c ADVAPI32!GetAclInformation+0x17
0006fe88 01006b12 00096d28 00000000 0006fec4 OGAEXEC+0x4b5a
0006febc 010090d6 00724e08 0006fed0 00000000 OGAEXEC+0x6b12
0006fed8 0100a183 01034320 00cc0004 00000000 OGAEXEC+0x90d6
0006ff10 0100a49e 00000001 00000000 00020b3e OGAEXEC+0xa183
0006ffa8 0101f9fb 019df984 019df9a4 7ffdb000 OGAEXEC+0xa49e
0006ffc0 7c817077 019df984 019df9a4 7ffdb000 OGAEXEC+0x1f9fb
0006fff0 00000000 0101f984 00000000 78746341 kernel32!BaseProcessStart+0x23

调用是从ADVAPI32!GetAclInformation进来的,ADVAPI32!GetAclInformation只是直接把参数push一遍然后传给了ntdll!RtlQueryInformationAcl,从上面信息看到传入ADVAPI32!GetAclInformation的pAcl参数就是NULL,根据MSDN,这必然会引发Access Violation:

The GetAclInformation function retrieves information about an access control list (ACL).

BOOL GetAclInformation(
  PACL pAcl,
  LPVOID pAclInformation,
  DWORD nAclInformationLength,
  ACL_INFORMATION_CLASS dwAclInformationClass
);

Parameters
pAcl
[in] A pointer to an ACL. The function retrieves information about this ACL. If a null value is passed, the function causes an access violation.

显然,这说明OGAEXEC.exe不应该在pAcl为NULL的情况下调用ADVAPI32!GetAclInformation(或者如果知道pAcl在调用时有可能为NULL的话,就应该搞个异常处理)。

进一步对OGAEXEC.exe的分析表明,OGAEXEC.exe调用该函数是为了获得文件odataext.dat的DACL信息。

具体地来说,OGAEXEC.exe调用GetFileSecurityW获取文件C:\Documents and Settings\All Users\Application Data\Office Genuine Advantage\data\odataext.dat的SecurityDescriptor:

.text:01006AD0
.text:01006AD0 loc_1006AD0:                            ; CODE XREF: sub_1006A24+A0j
.text:01006AD0                 lea     eax, [ebp+nLengthNeeded]
.text:01006AD3                 push    eax             ; lpnLengthNeeded
.text:01006AD4                 push    [ebp+nLengthNeeded] ; nLength
.text:01006AD7                 mov     [ebp+var_4], edi
.text:01006ADA                 push    edi             ; pSecurityDescriptor
.text:01006ADB                 push    DACL_SECURITY_INFORMATION ; RequestedInformation
.text:01006ADD                 push    [ebp+lpFileName] ; lpFileName
.text:01006AE0                 call    esi ; GetFileSecurityW

然后对得到的SecurityDescriptor,调用GetSecurityDescriptorDacl获得其中的DACL:

.text:01004AF5
.text:01004AF5 loc_1004AF5:                            ; CODE XREF: sub_1004AC0+27j
.text:01004AF5                 push    ebx
.text:01004AF6                 push    edi
.text:01004AF7                 lea     eax, [ebp+bDaclDefaulted]
.text:01004AFA                 push    eax             ; lpbDaclDefaulted
.text:01004AFB                 lea     eax, [ebp+pAcl]
.text:01004AFE                 push    eax             ; pDacl
.text:01004AFF                 lea     eax, [ebp+bDaclPresent]
.text:01004B02                 push    eax             ; lpbDaclPresent
.text:01004B03                 push    [ebp+SecurityDescriptor] ; pSecurityDescriptor
.text:01004B06                 call    ds:GetSecurityDescriptorDacl
.text:01004B0C                 test    eax, eax
.text:01004B0E                 mov     ebx, 0FFFFh
.text:01004B13                 mov     edi, 80070000h
.text:01004B18                 jnz     short loc_1004B33
.text:01004B18

对GetSecurityDescriptorDacl调用成功后的输出,OGAEXEC.exe做了这样的判断

.text:01004B33
.text:01004B33 loc_1004B33:                            ; CODE XREF: sub_1004AC0+58j
.text:01004B33                 cmp     [ebp+bDaclPresent], esi ; esi is 0/FALSE
.text:01004B36                 jnz     short loc_1004B49  ; if bDaclPresent is TRUE, pAcl can also be NULL
.text:01004B36
.text:01004B38                 cmp     [ebp+pAcl], esi
.text:01004B3B                 jnz     short loc_1004B49
.text:01004B3B
.text:01004B3D                 mov     [ebp+var_4], 8000FFFFh
.text:01004B44                 jmp     loc_1004C6E
.text:01004B44

OGAEXEC.exe的以上判断逻辑认为,只要返回的bDaclPresent为TRUE,那么返回的pAcl值就一定非NULL,只有bDaclPresent为FALSE才需要对pAcl是否为NULL进行判断,这样在bDaclPresent为TRUE的情况下,直接就对该pAcl值调用了GetAclInformation:

.text:01004B49 ; ---------------------------------------------------------------------------
.text:01004B49
.text:01004B49 loc_1004B49:                            ; CODE XREF: sub_1004AC0+76j
.text:01004B49                                         ; sub_1004AC0+7Bj
.text:01004B49                 push    2               ; dwAclInformationClass
.text:01004B4B                 push    0Ch             ; nAclInformationLength
.text:01004B4D                 lea     eax, [ebp+pAclInformation]
.text:01004B50                 push    eax             ; pAclInformation
.text:01004B51                 push    [ebp+pAcl]      ; pAcl
.text:01004B54                 call    ds:GetAclInformation ; cause access violation
.text:01004B5A                 test    eax, eax
.text:01004B5C                 jnz     short loc_1004B77

然而,根据MSDN中对GetSecurityDescriptorDacl函数的解释:

A value of TRUE for lpbDaclPresent does not mean that pDacl is not NULL. That is, lpbDaclPresent can be TRUE while pDacl is NULL, meaning that a NULL DACL is in effect. A NULL DACL implicitly allows all access to an object and is not the same as an empty DACL. An empty DACL permits no access to an object. For information about creating a proper DACL, see Creating a DACL.

也就是说,在此处当bDaclPresent为TRUE时,pAcl可能为NULL,这时的NULL DACL表示对该对象允许所有权限。而OGAEXEC.exe没有对这种情况进行判断,导致在bDaclPresent为TRUE的情况下直接把一个为NULL的pAcl指针传给了ADVAPI32!GetAclInformation,导致后者在ntdll!RtlQueryInformationAcl访问这个NULL指针,从而触发了Access Violation异常。

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞0
打赏
分享
最新回复 (1)
雪    币: 519
活跃值: 活跃值 (11)
能力值: ( LV12,RANK:230 )
在线值:
发帖
回帖
粉丝
hljleo 活跃值 5 2009-10-8 20:53
2
0
good job..
游客
登录 | 注册 方可回帖
返回