0

I have a user DOMAIN\User.Name that is according to whoami /GROUPS in somewhat over 200 windows domain groups.

When I try do determine all groups for this user using the WinAPI function ::NetUserGetLocalGroups() I get only 27 groups for said user:

#include <windows.h> 
#include <lm.h>
#include <string>

int main()
{
  //query the domain server for the groups of the user
  LPGROUP_USERS_INFO_0 pBuf = NULL;
  DWORD dwLevel = 0;
  DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
  DWORD dwEntriesRead = 0;
  DWORD dwTotalEntries = 0;
  NET_API_STATUS nStatus = MAX_NERR;

  std::wstring serverName(L"\\\\MyDomainNameDns");
  std::wstring userName(L"DOMAIN\\user.name");

  nStatus = ::NetUserGetLocalGroups(serverName.c_str(),
    userName.c_str(),
    dwLevel,
    LG_INCLUDE_INDIRECT,
    reinterpret_cast<PBYTE*>(&pBuf),
    dwPrefMaxLen,
    &dwEntriesRead,
    &dwTotalEntries);
}

dwTotalEntries is 27 and nStatus is 0, so it's not that I fetch only a part of all groups. Also I tried using ::NetUserGetGroups() instead but had no success either.

NOTE: Using .NET functionality System.Security.Principal.WindowsIdentity.GetCurrent().Groups indeed does give me all groups.

What could be the reason NetUserGetLocalGroups does not return get all groups as whoami or .NET / WindowsIdentity? What could be the difference between the groups returned/not returned?

Tromse
  • 230
  • 2
  • 9
  • 1
    *whoami /GROUPS* return groups from token. – RbMm Apr 01 '19 at 09:00
  • @RbMm What token? Can I obtain one (e.g. for the logged in user) and obtain the groups using using that token via the WinAPI? – Tromse Apr 01 '19 at 11:06
  • 1
    of course yes. process token. in what problem call `OpenProcessToken` and then `GetTokenInformation` with `TokenGroups` ? – RbMm Apr 01 '19 at 11:12
  • @RbMm I was able to obtain a process token with `::OpenProcessToken`, get token Information with `::GetTokenInformation` and iterate over the group SIDs looking up the name using `::LookupAccountSid`. Thanks so far. I still don't understand though why I see some groups only having the token, while I do see only part of them when not obtaining a token and using `::NetUserGetLocalGroups` – Tromse Apr 02 '19 at 08:21
  • this is different functions. with `GetTokenInformation` you look what is actually asigned for current user token. with `NetUserGetLocalGroups` you look in persistent sam database. question - what you actually need ? – RbMm Apr 02 '19 at 08:27
  • Maybe I get the question wrong, but, isn't that the point of "NetUserGetLocalGroups", returning only _local groups_, _not_ domain groups? Aren't you're extra 173 groups or so, domain groups? – Christian.K Apr 02 '19 at 10:23
  • @Christian.K The result of `NetUserGetLocalGroups` contains also domain groups. That is what confused me. I found a windows user group discussion that clarifies what is going on. See my answer below. @RbMm – Tromse Apr 02 '19 at 10:54

1 Answers1

0

After quite some more digging I found the following statement in a windows user group discussion:

Actually, NetUserGetLocalGroups / NetUserGetGroups do not handle nested or universal groups in windows 2000 native domains. Enumerating the SIDs from the token is the only reliable way.

So, in other words, use ::NetUserGetLocalGroups / NetUserGetGroups if you want direct group membership. If you want to know the group ownership in order to find out whether a user has the right to do something, use the token / SID way (e.g. using ::OpenProcessToken, ::GetTokenInformation and ::LookupAccountSid).

Example

A user is in the (domain local) group Employee. All employees have keycard access to the building, so the Employee group is am member of the HasBuildingAccess (domain local) group.

If you want to know, whether a user is (directly) in the Employee group, use ::NetUserGetLocalGroups. It contains the Employee group, but not the HasBuildingAccess group.

If you want to know however, whether a user has the right to access the building, enumerate the SIDs from the token. It will contain the HasBuildingAccess group.

Tromse
  • 230
  • 2
  • 9