安全脉搏之前发布过《谷歌安全团队公开Windows 8.1权限提升漏洞POC》。
来看#阿里巴巴安全研究实验室# @程大壮V 对“Windows: Elevation of Privilege in ahcache.sys/NtApphelpCacheControl 提权漏洞”的分析。
 win8.1_2

0x00 背景

Google Zero Project Team 在2014年的最后一天,公开了一个未修补的提权漏洞,并公开了poc代码。

详情参见:《谷歌安全团队公开Windows 8.1权限提升漏洞POC

0x01 漏洞描述

这个函数NtApphelpCacheControl,允许建立兼容性数据缓存并在新的进程被创建时重新使用。下面是这个函数的第一个参数。

win8.1_1

而在执行的过程中,普通用户只能查询,只有管理员权限的用户可以更新。

但它通过调用AhcVerifyAdminContext来验证Admin权限的时候,存在问题,只通过对比SID进行了判断,并没有深入判断Token的impersonation等级。

攻击者可以伪造一个类似的Token,从而进行攻击。

 

0x02 漏洞细节

漏洞产生的函数AhcVerifyAdminContext如下:

PAGE:0000000000016D64 ; int __cdeclAhcVerifyAdminContext(char, int, char, int, char, int, PVOID P)

PAGE:0000000000016D64 AhcVerifyAdminContextproc near         ; CODE XREF:AhcDriverDispatchDeviceControl:loc_1C16Cp

PAGE:0000000000016D64                                         ;AhcDriverDispatchDeviceControl+118p ...

PAGE:0000000000016D64

PAGE:0000000000016D64 arg_0           = byte ptr  8

PAGE:0000000000016D64 arg_8           = byte ptr  10h

PAGE:0000000000016D64 arg_10          = byte ptr  18h

PAGE:0000000000016D64 P               = qword ptr  20h

PAGE:0000000000016D64

PAGE:0000000000016D64                 push    rbx

PAGE:0000000000016D66                 push    rbp

PAGE:0000000000016D67                 push    rsi

PAGE:0000000000016D68                 push    rdi

PAGE:0000000000016D69                 sub     rsp, 28h

PAGE:0000000000016D6D                 mov     rbx, gs:188h

PAGE:0000000000016D76                 mov     edi, 0C0000022h

PAGE:0000000000016D7B                 call    cs:__imp_PsGetCurrentProcess

PAGE:0000000000016D81                 lea     r9, [rsp+48h+arg_10]

PAGE:0000000000016D86                 lea     r8, [rsp+48h+arg_0]

PAGE:0000000000016D8B                 lea     rdx, [rsp+48h+arg_8]

PAGE:0000000000016D90                 mov     rcx, rbx

PAGE:0000000000016D93                 mov     rbp, rax

PAGE:0000000000016D96                 xor    esi, esi

PAGE:0000000000016D98                 call    cs:__imp_PsReferenceImpersonationToken// 得到Token

 

PAGE:0000000000016D9E                 mov     rbx, rax

PAGE:0000000000016DA1                 test    rax, rax

PAGE:0000000000016DA4                 jnz     short loc_16DDC

PAGE:0000000000016DA6                 mov     rcx, rbp

PAGE:0000000000016DA9                 call    cs:__imp_PsReferencePrimaryToken

PAGE:0000000000016DAF                 mov     esi, 1

PAGE:0000000000016DB4                 mov     rbx, rax

PAGE:0000000000016DB7                 test    rax, rax

PAGE:0000000000016DBA                 jnz     short loc_16DDC

PAGE:0000000000016DBC             lea     r9, aFailedToGetEff ; "Failed to geteffective token"

PAGE:0000000000016DC3                 lea     rdx, aAhcverifyadmin ;"AhcVerifyAdminContext"

PAGE:0000000000016DCA                 mov     r8d, 3A1h

PAGE:0000000000016DD0                 xor     ecx, ecx

PAGE:0000000000016DD2                 call    AhcTracePrintf

PAGE:0000000000016DD7                 jmp     loc_16E6A

PAGE:0000000000016DDC ; ---------------------------------------------------------------------------

PAGE:0000000000016DDC

PAGE:0000000000016DDC loc_16DDC:                              ; CODE XREF:AhcVerifyAdminContext+40j

PAGE:0000000000016DDC                                         ; AhcVerifyAdminContext+56j

PAGE:0000000000016DDC                 lea     r8, [rsp+48h+P]

PAGE:0000000000016DE1                 mov     edx, 1

PAGE:0000000000016DE6                 mov     rcx, rbx

PAGE:0000000000016DE9                 call    cs:__imp_SeQueryInformationToken

PAGE:0000000000016DEF                 test    eax, eax

PAGE:0000000000016DF1                 jns     short loc_16E10

PAGE:0000000000016DF3                 lea     r9, aFailedToQueryT ; "Failed toquery token information.\n"

PAGE:0000000000016DFA                 lea     rdx, aAhcverifyadmin ;"AhcVerifyAdminContext"

PAGE:0000000000016E01                 mov     r8d, 3A9h

PAGE:0000000000016E07                 xor     ecx, ecx

PAGE:0000000000016E09                 call    AhcTracePrintf

PAGE:0000000000016E0E                 jmp     short loc_16E4F

PAGE:0000000000016E10 ;---------------------------------------------------------------------------

PAGE:0000000000016E10

PAGE:0000000000016E10 loc_16E10:                              ; CODE XREF: AhcVerifyAdminContext+8Dj

PAGE:0000000000016E10                 mov     rax, cs:__imp_SeExports

PAGE:0000000000016E17                 mov     rdx, [rsp+48h+P]

PAGE:0000000000016E1C                 mov     rcx, [rax]

PAGE:0000000000016E1F                 mov     rdx, [rdx]

PAGE:0000000000016E22                 mov     rcx, [rcx+108h]

//这里得到Sid

PAGE:0000000000016E29                 call    cs:__imp_RtlEqualSid; 

这里调用RtlEqualSid进行检查,看两个Token的Sid是否一致。

如果一致就返回正确了。

PAGE:0000000000016E2F                 test    al, al

PAGE:0000000000016E31                 jnz     short loc_16E40

PAGE:0000000000016E33                 mov     rcx, rbx

PAGE:0000000000016E36                 call    cs:__imp_SeTokenIsAdmin

PAGE:0000000000016E3C                 test    al, al

PAGE:0000000000016E3E                 jz      short loc_16E42

PAGE:0000000000016E40

PAGE:0000000000016E40 loc_16E40:                              ; CODE XREF:AhcVerifyAdminContext+CDj

PAGE:0000000000016E40                 xor     edi, edi

PAGE:0000000000016E42

PAGE:0000000000016E42 loc_16E42:                              ; CODE XREF:AhcVerifyAdminContext+DAj

PAGE:0000000000016E42                 mov     rcx, [rsp+48h+P] ; P

PAGE:0000000000016E47                 xor     edx, edx        ; Tag

PAGE:0000000000016E49                 call    cs:__imp_ExFreePoolWithTag

PAGE:0000000000016E4F

PAGE:0000000000016E4F loc_16E4F:                              ; CODE XREF:AhcVerifyAdminContext+AAj

PAGE:0000000000016E4F                 test    rbx, rbx

PAGE:0000000000016E52                 jz      short loc_16E6A

PAGE:0000000000016E54                 mov     rcx,rbx

PAGE:0000000000016E57                 cmp     esi, 1

PAGE:0000000000016E5A                 jnz     short loc_16E64

PAGE:0000000000016E5C                 call    cs:__imp_PsDereferencePrimaryToken

PAGE:0000000000016E62                 jmp     short loc_16E6A

PAGE:0000000000016E64 ;---------------------------------------------------------------------------

PAGE:0000000000016E64

PAGE:0000000000016E64 loc_16E64:                              ; CODE XREF:AhcVerifyAdminContext+F6j

PAGE:0000000000016E64                 call    cs:__imp_PsDereferenceImpersonationToken

PAGE:0000000000016E6A

PAGE:0000000000016E6A loc_16E6A:                              ; CODE XREF:AhcVerifyAdminContext+73j

PAGE:0000000000016E6A                                         ;AhcVerifyAdminContext+EEj ...

PAGE:0000000000016E6A                 mov     eax, edi

PAGE:0000000000016E6C                 add     rsp, 28h

PAGE:0000000000016E70                 pop     rdi

PAGE:0000000000016E71                 pop     rsi

PAGE:0000000000016E72                 pop     rbp

PAGE:0000000000016E73                 pop     rbx

PAGE:0000000000016E74                 retn

PAGE:0000000000016E74 AhcVerifyAdminContextendp

 

 0x03 漏洞利用

像这种提升权限的漏洞,要利用的话,需要对系统权限管理这块非常的熟悉。

Google的大牛们直接给出了POC, 现在我们来分析一下POC是如何实现利用的。

漏洞利用有如下几步:

(1)得到一个Local System的Token, Sid为:S-1-5-18的Token

(2)构造一个ApphelpCacheControlData的结构,里面包含regsvr32.dll包等相关的信息。

(3)将Token赋予本线程,通过调用SetThreadToken

(4)执行status =fNtApphelpCacheControl(AppHelpUpdate, &data);将data的数据更新到Cache中。

(5)执行ShellExecuteW(nullptr, verb, argv【1】, dllpath.c_str(), nullptr, SW_SHOW);行它会调用regsvr32.dll 并执行TestDll.dll中的代码。从而达到权限提升的目的(其实是绕过UAC)。

0x04 结论

这个漏洞利用,其实是通过绕过UAC来执行代码的。

如果在普通用户权限下,执行操作的时候,会弹出UAC的提示。

所以必须是admin的用户,执行SetThreadToken的时候,其实已经将Local System的权限赋予了当前的线程。

但其实真正奇妙的是使用ComputeDefaults.exe,这个程序在直接使用的时候,是没有UAC的提示。

作者提示,这样没有UAC提示的程序还有很多。

所以通过它来调用regsvr32.dllTestDLL.dll这个,也不会有UAC的提示。

我们换做别的,比如cmd.exe,来执行的时候,是会有UAC的提示的。不会达到目的。

最后发一个执行成功的截图

win8.1_poc

 

0x05 参考

https://code.google.com/p/google-security-research/issues/detail?id=118

 

【本文来源:程大壮 SP小编整理发布】

源链接

Hacking more

...