Remote query of priviliges for local principals

As part of investigations, you may need to query which privilege is held by a local principal, such as a local user or group. There is of course ‘whoami’ which tells you everything you need to know when logged in on a given system. And there is the ProcessExplorer utility which is incredibly powerful, and can tell you all that and more about a logged in user.

However you may need to do a scan across multiple systems to verify that a given group has a specific privilege. This is the action I will write about here. I try to do as much as possible with Powershell, because it is ubiquitous, very powerful, and lends itself well to programming systems administration tasks.

There is a convenient PowerShell module which facilitates access to the Local Security Authority via .NET marshaling. It used to be available on technet but is now only found on GitHub.

For the sake of testing, I created a group named ‘TestGroup’ on my local machine, and on a remote machine. In the real-world use case I had, the group is one that exists on all computers. That doesn’t need to be the case, but in this case I added it locally to explain a problem a bit later.

On the remote computer, I used the Local Security mmc to grant the Impersonation privilege to that local group:

The PowerShell Module can enumerate privileges locally and remotely, for both local or domain principals. If we want to know what privileges ‘TestGroup’ has, the call seems obvious.
However, that yields a surprising result:
We know TestGroup holds at least 1 privilege so the output should reflect that. Yet this function keeps reporting there are no privileges held. If we inspect the code for that function closer, it rapidly becomes obvious what is happening. The function connects to the remote LSA via a wrapper class and enumerates the rights
The ‘enumerate’ method translates the account name to a SID, and passes the SID for actual lookup to the LSA:
Oddly, the account name is translated to a SID, seemingly without taking the computer name into account. Following the trail to the Sid class finally shows the reason for the issue.

The account can be supplied either as an actual SID, or as a name which is then translated to a SID. The problem here is that if we supply the name of a local principal for looking up the privileges on a remote computer, we mean the local group on ‘that’ system, not the local group on this system. Logically, the remote group will have a different SID. This can be demonstrated easily enough:

So with that in mind, the solution is trivial. We implement our own SID translation, and pass that SID to the module function so that it immediately contacts the remote LSA with that SID and skips the translation step:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s