Why does KB 118626 use AccessCheck to check if you're a member of the administrators group?
Eagle Eyed reader Jens Geyer sent me an email yesterday asking:
There's a KB article, where there is an example code how to determine if the current process/thread is running from admin account. The sample code changed in the newest revision of that KB article.
https://support.microsoft.com/kb/118626
The old version was testing the group list of the token, whether one of the groups is the predefined admin group. THe new code does something different: They create a SD, with a DACL containing exactly one Access-Allowed-ACE with the Admins Group SID. Then an AccessCheck() is performed on this SD to determine the function result.
My question now is: What is the reason behind the change? Whats wrong with the old code?
Unfortunately the KB article does not mention anything about the reasons. I hope, you can help or at least know someone, who can.
Humorously enough, I wrote the sample code for the original KB article many, many years ago, someone picked up the code and added it to a KB article.
In pseudo-code, the sample did:
if (!OpenThreadToken(&htoken))
OpenProcessToken(&htoken);GetTokenInformation(TokenGroups, &groups)
foreach (groupSid in groups)
{
if (groupSid == BuiltinAdministratorsSid)
{
return TRUE;
}
}
return FALSE
In other words, it iterated over the token's groups and looked to see if the group was active in the token.
This worked great at the time it was written (NT4), but by the time that Windows 2000 came out, the sample ceased to be accurate. The thing that broke the sample was the addition of the concept of a "Restricted Token". Essentially a restricted token is a token which has had several of the groups and privileges disabled in the token. Vista's UAC feature is based on restricted tokens, as were Windows XP's Safer APIs.
The problem with the previous code is that it didn't take restricted tokens into account. Fortunately the AccessCheck function does. So the KB people updated the sample code to reflect this change - first off they pointed to the CheckTokenMembership API, and for those users that can't use that API, they put up a replacement version of the function in the original KB (in pseudo-code):
if (!OpenThreadToken(&htoken))
OpenProcessToken(&htoken);psidAdministrators = AllocateAndInitializeSid(...);
pACL = new BYTE[ACLSize];
InitializeACL(pACL);
AddAccessAllowedACE(pACL, READ_ACCESS, psidAdministrators);
SetSecurityDescriptorDACL(psd, pACL);
return (AccessCheck(psd, htoken, READ_ACCESS));
And now you know "The Rest of the Story" :)
Comments
Anonymous
March 14, 2007
PingBack from http://winblogs.security-feed.com/2007/03/14/why-does-kb-118626-use-accesscheck-to-check-if-youre-a-member-of-the-administrators-group/Anonymous
March 14, 2007
It's amazing how you hear Paul Harvey when you read And now you know "The Rest of the Story"Anonymous
March 14, 2007
Who's Paul Harvey? Old fogey alert!Anonymous
March 14, 2007
Your psuedocode has a memory leak.Anonymous
March 15, 2007
Wednesday, March 14, 2007 4:26 PM by Alex > Your psuedocode has a memory leak. The advantage of pseudocode is that you can rely on pseudogarbage collection and pseudolose nothing. Let's reserve these worries for real code.Anonymous
March 15, 2007
Thank you Norman, I could not have said it better myself.Anonymous
March 27, 2007
Is it possible to update the sample code to make it work on Windows Vista ? The current version works for Win2k, XP, 2k3, but on Vista it returns FALSE for all accounts.Anonymous
March 28, 2007
Jason, the sample should work when run from an elevated command prompt. When you're running on Vista, you're NOT an administrator normally.