Tuesday, March 23, 2010

Understanding Impersonation

Understanding Impersonation


Process Token

Whenever a process is created, its process access token is also created in the kernel. This process token is used when access permission check is required. Roughly speaking, process token is the user identity of the process. For example, if the process tries to access system resources such as registry or file, the process shows its process token and the operating system checks access permission by using security descriptor (SD) of the system resources. SD contains the complete list of who is allowed and who is denied. Generally, all threads in the process inherit the process token, “unless” thread is impersonating.

Let’s take an example. I ran SQL Configuration Manager, attached the debugger and picked one of threads (thread#1). To inspect the thread token, switch to the thread#1 and run !token –n.
0:000>  ~1s
0:001>  !token -n
Thread is not impersonating. Using process token...
TS Session ID: 0x1
User: S-1-5-21-2127521184-1604012920-1887927527-570548 (User: TDomain\yongslee)
Groups:
00 S-1-5-21-2127521184-1604012920-1887927527-513 (Group: TDomain\Domain Users)
Attributes - Mandatory Default Enabled
01 S-1-1-0
Attributes - Mandatory Default Enabled
.....
.....   
Impersonation Level: Anonymous
TokenType: Primary
Is restricted token: no.
As bold-face text says, the thread is not impersonating any and using primary access token which is the process token.

Impersonation and Thread Token

Sometimes thread might need to impersonate other user. This basically means that the thread does not use process access token and rather uses different user token. This scenario often occurs when client is accessing server resources. To access server resources, the server code impersonates (and acts as) the client identity and performs resource access with it. If the client user doesn’t have permission to access server resource, it throws access denied.

To see how it works, let’s run SQL Configuration Manager and invoke SQL WMI provider. SQL WMI provider is run as Network Service account in the wmiprvse.exe process and thus its process token is representing Network Service. WMI providers are typically using impersonation so we expect that worker thread in WMI provider is using client account, not Network Service. If worker thread uses Network Service, it might be a big security hole.

(1) Run SQL Configuration Manager (SQLCM)

=> Whenever SQLCM is launched, new SQL WMI provider process (wmiprvse) will be created (if already doesn’t exist)

=> Run tlist.exe to find SQL WMI provider

C> tlist –m sqlmgmprovider.dll



(2) Attach to SQL WMI provider by using windbg

C> windbg –p 2202 (ex: 2202 = pid of wmiprvse.exe)

(3) Set breakpoint in one of SQL WMI classes. Let’s try SqlServiceAdvancedProperty.

To break in when Advanced properties is clicked, set bp against this method and keep debugger going.
0:011> bp sqlmgmprovider!SqlServiceAdvancedProperty::EnumerateInstances
0:011> g
(4) In SQLCM, select SQL Server Services -> doubleclick SQL Server (MSSQLSERVER) to bring up the Properties page -> Click Advanced tab to display advanced properties. (This will call SqlServiceAdvancedProperty:: EnumerateInstances method in SQL WMI provider)

Now, breakpoint will be hit and we can check thread token by using !token command.
Breakpoint 0 hit
eax=541c1d58 ebx=80041024 ecx=54214588 edx=6d599bc9 esi=54214588 edi=0095e3c8
eip=541def70 esp=00deefb8 ebp=00deefc8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
sqlmgmprovider!SqlServiceAdvancedProperty::EnumerateInstances:
541def70 8bff            mov     edi,edi
0:007> !token -n
TS Session ID: 0x1
User: S-1-5-21-2127521184-1604012920-1887927527-570548 (User: TDomain\yongslee)
Groups:
00 S-1-5-21-2127521184-1604012920-1887927527-513 (Group: TDomain\Domain Users)
Attributes - Mandatory Default Enabled
....
Primary Group: S-1-5-21-2127521184-1604012920-1887927527-513 (Group: TDomain\Domain Users)
Privs:
15 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default
19 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default
20 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default
Auth ID: 0:5eeba
Impersonation Level: Impersonation
TokenType: Impersonation
Is restricted token: no.
The thread token here is impersonating and acts as TDomain\yongslee, not using Network Service. Please note this user is the same one that invoked SQLCM process. So even if the SQL WMI provider process is run as Network Service, actual worker thread is using the client user principal that makes WMI request. If the client application is run in low privilege account and the account cannot access system resource such as registry, the WMI request accessing registry resource won’t be successful.

Impersonation in SQL WMI

Then how can the worker thread in SQL WMI provider impersonate the client principal? It is using internally WbemCoImpersonateClient method in WMI framework API. Before this method is called, the worker thread is using process token (Network Service). Once the WbemCoImpersonateClient is executed, the thread acquires impersonation token.
0:010> bp framedyn!WbemCoImpersonateClient
0:010> g
framedyn!WbemCoImpersonateClient:
0:007> !token –n    //Check token before impersonation
Thread is not impersonating. Using process token...
TS Session ID: 0
User: S-1-5-20 (Well Known Group: NT AUTHORITY\NETWORK SERVICE)
.....
Impersonation Level: Anonymous
TokenType: Primary
Is restricted token: no.
0:007> gu            // Execute WbemCoImpersonateClient()
framedyn!CWbemProviderGlue::CheckImpersonationLevel+0x39:
0:007> !token –n     // Check token after impersonation
TS Session ID: 0x1
User: S-1-5-21-2127521184-1604012920-1887927527-570548 (User: TDomain\yongslee)
.....
Impersonation Level: Impersonation
TokenType: Impersonation