2

What I'm trying to understand is whether LogonUser with LOGON32_LOGON_INTERACTIVE produces restricted token or not? Here is my code:

int davai()
{
FILE * fp;

fp = fopen ("C:\\tmp\\davai.txt", "a");
fprintf(fp, "shevedi davai");
fflush(fp);

HANDLE token = NULL;
HANDLE dupToken = NULL;

if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &token))
{
  fprintf(fp, "davai: OpenProcessToken cheijva. %d\n", (int)GetLastError());
  fflush(fp);
}

if (DuplicateTokenEx(token, MAXIMUM_ALLOWED, NULL, SecurityDelegation,
                          TokenPrimary, &dupToken) == 0)
{
  fprintf(fp, "davai: OpenProcessToken DuplicateTokenEx. %d\n", (int)GetLastError());
  fflush(fp);
}

PTOKEN_GROUPS pPrivilegesToken = NULL;
DWORD cbSize = 0;

GetTokenInformation(dupToken, TokenGroups, NULL, 0, &cbSize);

pPrivilegesToken = (PTOKEN_GROUPS) LocalAlloc(LPTR, cbSize);

if (GetTokenInformation(dupToken, TokenGroups, 
                             pPrivilegesToken, cbSize, &cbSize) == FALSE)
{
  fprintf(fp, "davai: GetTokenInformation cheijva. %d\n", (int)GetLastError());
  fflush(fp);
}

char * gio;

for (ULONG i = 0; i < pPrivilegesToken->GroupCount; i++)
{
  if (ConvertSidToStringSid(pPrivilegesToken->Groups[i].Sid, &gio) == 0)
  {
    fprintf(fp, "davai: ConvertSidToStringSid cheijva. %d\n", (int)GetLastError());
    fflush(fp);
  }
 
  fprintf(fp, "Value: %s attribute -> %ld \n",gio, pPrivilegesToken->Groups[i].Attributes);
  fflush(fp);
}

LocalFree (gio);

return 1;
}

which is run by a token which was obtained by LOGON32_LOGON_INTERACTIVE. And my output is this:

Value: S-1-5-21-1018819917-2920201817-244685803-513 attribute -> 7 
Value: S-1-1-0 attribute -> 7 
Value: S-1-5-21-1018819917-2920201817-244685803-1000 attribute -> 7 
Value: S-1-5-32-544 attribute -> 16 
Value: S-1-5-32-545 attribute -> 7 
Value: S-1-5-4 attribute -> 7 
Value: S-1-2-1 attribute -> 7 
Value: S-1-5-11 attribute -> 7 
Value: S-1-5-15 attribute -> 7 
Value: S-1-5-5-0-19732224 attribute -> -1073741817 
Value: S-1-5-64-10 attribute -> 7 
Value: S-1-16-8192 attribute -> 96 

Notice the 16 with Administrators Group. If I use LOGON32_LOGON_BATCH I get this:

S-1-5-21-1018819917-2920201817-244685803-513 attribute -> 7 
Value: S-1-1-0 attribute -> 7 
Value: S-1-5-21-1018819917-2920201817-244685803-1000 attribute -> 7 
Value: S-1-5-32-544 attribute -> 15 
Value: S-1-5-32-545 attribute -> 7 
Value: S-1-5-3 attribute -> 7 
Value: S-1-2-1 attribute -> 7 
Value: S-1-5-11 attribute -> 7 
Value: S-1-5-15 attribute -> 7 
Value: S-1-2-0 attribute -> 7 
Value: S-1-5-5-0-20537541 attribute -> -1073741817 
Value: S-1-5-64-10 attribute -> 7 
Value: S-1-16-12288 attribute -> 96 

I also found that some people have same problem as I do.

  1. IsAdminUser returns incorrect value
  2. In Windows: How do you programatically launch a process in administrator mode under another user context?
  3. How to call LogonUser() to get a non-restricted full token inside a Windows Service with UAC enabled?

It seems to me that LOGON32_LOGON_INTERACTIVE produces restricted token (or is it that just different types of logons produce different kind of token?), Is there any documentation that would verify that I'm right?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Rasty
  • 303
  • 3
  • 14
  • The `Win32:API` is written in C (as XS module) you can check the implementation of the [IsAdminUser here](https://metacpan.org/source/JDB/Win32-0.52/Win32.xs#L408) – kobame Mar 28 '17 at 16:28
  • Are you asking about UAC elevated tokens? Restricted token is a specific thing, please don't use that term unless you actually are talking about restricted tokens! A restricted token is more restricted than your regular login token. – Anders Mar 28 '17 at 18:57
  • Yes. It gives you a UAC ("LUA") filtered token. Documentation? Not really and no reason. The documentation on UAC says you get a filtered token. The interesting part is that other logon types (BATCH, etc.) don't produce a filtered token. That's what really requires documentation. Where does it say that there are logon types that are exempt from UAC? – conio Mar 28 '17 at 19:34
  • @Anders: You're right, but the documentation (and symbols) is messed up enough so it's understandable. Filtered tokens are too "more restricted than your regular login token", so your explanation doesn't describe the difference. Serves to prove the complexity of this stuff. – conio Mar 28 '17 at 19:41
  • `LOGON32_LOGON_INTERACTIVE` used when user "usual" way login in windows. known thing that begin from vista, when *UAC* on, all admin users (except built-in admin) got filtered token, where Administrative group is disabled and many privileges removed – RbMm Mar 28 '17 at 20:03
  • Turns out that when you use `LOGON32_LOGON_INTERACTIVE` you get *two* tokens. The handle returned from `LogonUser` is for the limited token, but you can open a handle to the elevated token by passing the limited token to `GetTokenInformation` with the `TokenLinkedToken` option. (I've updated my answer on the linked question accordingly.) – Harry Johnston Mar 28 '17 at 23:25
  • @HarryJohnston - yes, 2 token can be created during interactive logon. the second filtered (restricted) token is created from elevated by call `NtFilterToken` (or can assume `CreateRestrictedToken`) - how this is done - http://stackoverflow.com/a/43082015/6401656 – RbMm Mar 29 '17 at 00:08
  • 2
    ... to follow up on my previous comment, it turns out that in order to get a usable elevated token using that approach you must have SeTcbPrivilege. Typically you will only have this privilege if you are running as local system. Otherwise, you'll have to use `LOGON32_LOGON_BATCH` as previously discussed. – Harry Johnston Mar 29 '17 at 01:42
  • @HarryJohnston Could you please tell me how did you know that `SeTcbPrivilege` is needed? I've searched for `GetTokenInformation ` and `TokenLinkedToken ` and could not find such information. – Rasty Mar 29 '17 at 07:22
  • @Rasty - look [this](http://stackoverflow.com/a/39403260/6401656) answer and [this](https://ibb.co/d00ska) screenshot – RbMm Mar 29 '17 at 09:21
  • @Rasty, I wasn't initially aware that any privilege was needed, which is why I didn't mention it in my original comment. RbMm pointed out that my approach didn't work as expected and so I did some tests which found that he was right. However, it seemed unlikely that it would be impossible to get the real elevated token, so I did some more testing. Checking SeTcbPrivilege in particular was an educated guess which turned out to be correct. If it hadn't, my next move would have been to enable *every* privilege, and if that worked it would just be trial and error to identify which one helped. – Harry Johnston Mar 29 '17 at 20:07
  • ... sometimes the information isn't already out there and you have to research it yourself. It is a useful skill to cultivate. (Although you do have to also develop a sense of what you can sensibly rely upon as being a stable feature of the operating system, and what is just an implementation detail that might change without notice. In my judgement, this behaviour is likely to be stable.) – Harry Johnston Mar 29 '17 at 20:08

1 Answers1

3

Does LOGON32_LOGON_INTERACTIVE give restricted token?

Yes, for all interactive logon types : { Interactive, RemoteInteractive, CachedInteractive, CachedRemoteInteractive }

let debug lsass.exe and look what happen during call to LsaApLogonUserEx2 (this function is called in context of lsass when client process called LsaLogonUser or it shell LogonUser)

if login is ok, the lsass must create new token for logged user. this done in function LsaBuildAndCreateToken (of course this is internal implementation and name of this function can changed from version to version, but general how it worked - unchanged). so i trace this function under debugger - look at call tree at the right (this is for interactive logon) enter image description here

look for red squire - here in ESI - LogonType - SECURITY_LOGON_TYPE enumeration value

so code in general is next:

    SECURITY_LOGON_TYPE LogonType;
    switch (LogonType)
    {
    case Interactive://2
    case RemoteInteractive://10 
    case CachedInteractive://11
    case CachedRemoteInteractive://12
        // optimization (LogonType == 2) || (LogonType - 10) <= 2
        BOOLEAN b, c;
        if (0 <= LsapShouldSplitToken(Sid, &b,&c) && b)
        {
            LsaSplitElevatedToken(..)
        }
        break;
    }

this mean that lsass try restrict ONLY INTERACTIVE logon types, if will be another logon type, say Batch - token will never be filtered.

next interesting point - let look for LsapShouldSplitToken function

enter image description here

who know x64 - can understand code :) in general if LUA not enabled - dont filter token. if global variable LsapGlobalFilterAdministratorToken is false - check are user is built-in admin - check RID of Sid - are it 0x1f4 - DOMAIN_USER_RID_ADMIN (in other words built-in admin restricted only when LsapGlobalFilterAdministratorToken true - based on global comp politics (gpedit.msc) ) - and returned result of query 10+4=0x14=TokenElevation and returned value of TokenIsElevated

so if TokenIsElevated is true lsass call (not forget only for Interactive logon type) LsaSplitElevatedToken - what this function is doing visible in image:

created additional logon session (elevated and not elevated process for same user run in different logon sessions), created else one token (LsapCreateTokenObject) and it filtered by call NtFilterToken(hToken, LUA_TOKEN, 0, 0, 0, &hNewToken) (the win32 api CreateRestrictedToken is shell over NtFilterToken)

RbMm
  • 31,280
  • 3
  • 35
  • 56
  • And one more question what debuger did you use? I want to learn it too :) – Rasty Mar 29 '17 at 06:43
  • 1
    @Rasty - unfortunately this debugger exist only in single version and nobody interesting in it. use better WinDbg – RbMm Mar 29 '17 at 09:19