Sunday, 15 August 2004

Running with reduced privileges

I know I have to get to it sometime. In the current climate, anything you can do to mitigate the effects of a successful attack is worthwhile - and there's no sign of things letting up.

So I've taken my normal user account out of the Administrators group - I'm just a user again.

Now, clearly, as a power user, a developer, an occasional gamer and the machine owner, I still need to be able to launch programs as an Administrator. The runas tool is helpful here! However, there are times when you want a program to run with elevated privileges, but in your own context.

Aaron Margosis, a Microsoft consultant, has come up with a couple of useful tools. The first is a batch file which automates the process of adding your account to the Administrators group, creating a new shell, then removing the account again. The second is a toolbar which shows how privileged you are, in IE and Explorer.

If you're familiar with how Windows authorization works, feel free to skip this paragraph. Windows authorizes users against resources by comparing access control lists against the SIDs (Security IDs - internal representations of user accounts or security groups) in your token. The token can either be a primary token or an impersonation token. You typically get a primary token by logging on; servers can temporarily assume another identity by impersonating their client. Also included in your token are your privileges - actions you're allowed to take which may override the ACLs or allow other actions (e.g. shutting down the system). Privileges are orthogonal to access rights. The token is a cached copy of what you were allowed when you logged on - it contains the SIDs for all groups you were a member of and the privileges assigned to all SIDs.

Adding yourself to the Administrators group therefore has no effect until you next log on. Aaron's batch file gets round this by using runas to create a new logon session and hence a new token. You cannot replace the primary token for a running process - you can only create a process with a different token by calling CreateProcessAsUser.

The downsides to Aaron's batch file are two: one, that it requires you to type both the Administrator and your own password; two, that there's a window where your account is explicitly in the Administrators group (between typing the Administrator's password and typing your own).

This second one is possibly a risk. If your system crashes at this point, you're likely to still be in the Administrators group when you restart. If a service running with your credentials starts in this window, it will have privileges you didn't expect. A network logon with these credentials will also gain administrative privileges.

Can we do better? I think so. The LsaLogonUser function takes a TOKEN_GROUPS parameter which allows us to arbitrarily add groups to the new token, assuming successful authentication. The spike I put together over the last two days suggests that any privileges awarded to the (enabled) SIDs added to the token are also added to the token. This only requires us to supply the user's password - we don't need the administrator's. We can't totally automate it because Windows doesn't store the authenticated password in plain text - unless we circumvent things further, e.g. by adding a 'network provider' so that NPLogonNotify gets called with the plain-text password, and storing this somewhere. This would of course be a very bad idea, enabling the possibility that the plain-text password could be disclosed.

Lest you think this is a horrible hole in the NT security model, I'll point out that to do this, you must have a trusted connection to the Local Security Authority. To get one of these, you must call LsaRegisterLogonProcess, which requires the 'Act as part of the operating system' (SE_TCB_NAME) privilege (see what I mean about privileges being different from access rights?). In essence, that means running under the LocalSystem security context.

So where from here? Basically, I need to write a service which will listen for local requests (probably through RPC) and use the supplied credentials to create a token then create the appropriate process. This is going to be an adventure because before yesterday I'd never written a service! I'll be writing it in C++ because quite frankly there'd be no benefit in using C# due to the amount of P/Invoke marshalling required. I'll have to learn how to write RPC servers and clients, work out which logon provider to call (obviously the same one that the user used!) and how to write events to the event log. I'll also need to design access control so administrators can control who gets to do this.


Kaarthik said...

So.. Did you finally write the utility ?

Mike Dimmick said...

I'm working on it! See for where I've got to. A lot of the time I don't want to code when I get home from work...