Service Accounts


Services normally run under one of three specially defined service accounts or as an ordinary user:

  • Local system  Also known simply as SYSTEM, this is the Windows equivalent of the Unix “root” account and is the most powerful local account in Windows. Although administrators could configure their own accounts to do anything the local system account can do, the local system can do nearly anything by default because the account is a member of the Administrators group and is granted nearly all privileges, and the privileges are enabled by default. You should only run your service as local system if no other account will work and if you’re willing to do a lot of work to ensure that your service is secure and won’t give users an opportunity to escalate privilege. While it is tempting to run your service as local system during initial development, you could be setting yourself up for problems later when you run under a less-privileged account. If you have to run as local system, read the next section on privileges carefully, and only enable those absolutely needed by your service.

  • Local service  This account has few privileges locally and only amounts to a normal user for the most part, except for the right to create global objects (SE_CREATE_GLOBAL_NAME), which can have some interesting implications, and the right to impersonate clients (SE_IMPERSONATE_NAME). Note that if you’re only identifying clients, SE_IMPERSONATE_NAME isn’t needed. Across the network, services running under the local service account will authenticate as the anonymous account, which could be a problem or a feature, depending on what you’re trying to do.

  • Network service  This is the account to use when your service has to authenticate across the network as the computer account. As of Windows 2000, computer accounts are just variants on normal user accounts and can be added to ACLs and groups. Computer accounts are in the form of Domain\ComputerName$. Other than network authentication, network service has the same rights as local service.

  • Domain or local user account  You can run services under any user account that can log on to the system. Although this is sometimes the right choice, password management can be a problem. The best thing to do if you’re going to take this approach is to make two accounts; put them in an appropriate group; and when password changes are required, cycle all the services from account A to account B.

Even though the local service and network service accounts are a huge improvement over running all services as local system, there are still a number of problems. If your service needs access to some specific resource, that resource ends up getting an ACL entry added for local service or network service. If any other service running under that account is compromised, your resource is now available to the attacker. The various services running under these accounts are also vulnerable to attack by each other. If the attacker is clever (and many are) and having a good day, they may even find ways to escalate privilege to a local system.

The solution to the problem of setting ACLs for specific service resources is to use a new type of SID in your access control list–the service SID. The code to set the service SID is simple:

 DWORD SetServiceSid( SC_HANDLE hSvc, DWORD dwServiceSidType ) {    SERVICE_SID_INFO SvcSidInfo;    DWORD dwErr = ERROR_SUCCESS;    SvcSidInfo.dwServiceSidType = dwServiceSidType;    if( !ChangeServiceConfig2( hSvc,                               SERVICE_CONFIG_SERVICE_SID_INFO,                               &SvcSidInfo ) )    {       wErr = GetLastError();    }    return dwErr; }

There are three values defined for dwServiceSidType:

  • SERVICE_SID_TYPE_NONE–This doesn’t do anything, and the service will behave like a legacy service.

  • SERVICE_SID_TYPE_UNRESTRICTED–This setting adds the service SID to the process token for the service. This allows you to ACL resources to your specific service but doesn’t keep your service from accessing other resources that may be inappropriate.

  • SERVICE_SID_TYPE_RESTRICTED–This adds the service SID to the process token, and it creates a set of restricted SIDs in the token as well. The restricted SIDs placed into the token are everyone, write-restricted, the logon ID SID, and the service SID.

When a process or thread token contains restricted SIDs, all the access checks must go through two passes. The first is to see if the normal SIDs enabled in the token grant the access requested. If access is granted, then a second check is performed to see if access is granted on the basis of the restricted SIDs. Note that different user accounts could satisfy both checks–for example, the regular check might be granted because user David has access, and the second check might be granted because the write-restricted SID also has access. What this implies is that the SERVICE_SID_TYPE_RESTRICTED option means that your service can only open resources ACL’d to everyone, the specific service SID, and the write-restricted SID.

image from book
Figure 5-1: Diagram of an access check against a restricted token.

As an example, the sample service has a debug log file. Because having clients connect to a named pipe implies that you’re implementing a state machine, state transitions can be complex and hard to debug, especially when considering error states. Having a log file gives you an easy way to print out verbose information about what’s happening inside the sample service. When we install and run the service, if we fail to provide a full path to the file, we find that it gets created in %systemroot%\system32, which requires administrator-level access to add files, and which the process would have if it were running as local system. A better solution is to put the log file in a handy directory used for temporary files–say, for example, c:\scratch. Here’s how you can give the sample service access to the directory in order to create the log file:

 c:\scratch>cacls . /e /g "NT Service\VistaService":c

If you’re not familiar with cacls, what this translates to is “add an ACE that grants change access to this directory (“.”) to the VistaService service account”–assuming you’ve already installed the service, which is why we install the service first in our example. Note that while cacls is still supported on Windows Vista, icacls is a more versatile tool, and should be used for most ACL editing tasks, although it isn’t currently available for older operating systems.

As it turns out, if you’re running with SERVICE_SID_TYPE_RESTRICTED, then you can end up creating named objects that you don’t have enough access to. When you create persistent objects, the ACL will depend on the inherited permissions from the parent directory or registry key. When creating named objects, the permissions are still inherited, but are inherited from the BaseNamedObjects, and this varies depending on whether it is an event, a named pipe, or some other object. BaseNamedObjects can be thought of as the root directory for non-persistent named objects. With most of the objects you can create in Windows, you can specify a security descriptor at creation time, and if you’re using SERVICE_SID_TYPE_RESTRICTED, you may need to do so. In our sample application, when we set

SERVICE_SID_TYPE_RESTRICTED, it failed to initialize because although the service could create the first instance of the named pipe, it didn’t have the access needed to create additional instances. Other types of objects could have similar problems. Unlike ordinary files and registry keys, the permissions needed for a service SID will be generated uniquely for each system and will need to be looked up, which means that you’ll either need to drop to the lower-level security APIs, or you’d have to look up the SID, translate it to a SID string, and then use it with your SDDL string. If you’re doing initial development, you might find it convenient to run “sc showsid” on the service, although we’d advise just looking up the SID with Lookup-AccountName.

One advantage to specifying an ACL when creating an object is that you get to put exactly the access on the object that you need. This also allows you to avoid having race conditions between creating something and then subsequently setting permissions. The named pipe we use in our example was set to system:F, NT Service\VistaService:F, and interactive:Read, and synchronize, which can’t be represented in a very readable form in SDDL, because we’re using a user that isn’t defined by SDDL, which would have to be represented as an SID string specific to that system. This implies that the flag set to deny network access on the pipe is redundant, since no account that could access the pipe from the network has any access. To see exactly how this was done, take a look at the CreatePipeDacl function in VistaService.cpp.



Writing Secure Code for Windows Vista
Writing Secure Code for Windows Vista (Best Practices (Microsoft))
ISBN: 0735623937
EAN: 2147483647
Year: 2004
Pages: 122

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net