(This is part 4 of our series of posts on service hardening.)
A service can be configured to be write-restricted, in addition to having a per-service SID. To do so, you specify a SID type of "Restricted" when configuring your service (see our previous post “Per-service SID”). In that case the process hosting your service will run with a (new to Windows Vista) "write-restricted" token.
Hmmm, what is this animal, and what does it mean?
You may have heard of (or maybe be familiar with) restricted tokens. There are several definitions for those, one of which is a token issued from the CreateRestrictedToken API. We like to think of restricted tokens as tokens that have Restricting SIDs. When the system evaluates access to a resource, if there are restricting SIDs, the evaluation is made with two independent passes. The first pass uses the User SID and the Group SIDs, and the second pass uses the Restricting SIDs. For access to be granted, both passes must succeed. What that means is that Restricting SIDs can only be used to restrain access that a user account would have to start with but not broaden it in any event. Another case of the recurring "always restrain, never broaden" scheme.
We see restricted tokens along with the S-1-5-12 Restricted Code SID as early attempts to run applications with lower privilege and were used by "Run As…" with the "Protect my computer and data from unauthorized program activity” checkbox (no longer in Vista). In addition to Windows SDK documentation, you may want to check out blogs from Aaron Margosis and Larry Osterman for comments on these topics as well as Keith Brown's Programming Windows Security.
A write-restricted token (new to Windows Vista) is one that is flagged as WRITE_RESTRICTED (have a look at winnt.h). With a write-restricted token, the evaluation of the Restricting SIDs is only effective for write access checks. So a write-restricted token can be seen as less restrictive than a restricted token which is restricted for all types of accesses, and not only writes.
The write-restricted token for a "Restricted" service will have the following restricting SIDs: the per-service SID, the logon SID, the Everyone SID, and the (new to Vista) write-restricted SID (S-1-5-33 or NT AUTHORITY\WRITE RESTRICTED). The per-service SID and the write-restricted SID are also added to the Group SIDs. What does that mean?
· Writes are only possible by virtue of the service SID, the logon SID, Everyone SID, or write-restricted SID, and not the service account nor its groups. Reads are unaffected.
· The write-restricted SID allows for granting access to write-restricted services as a class, without forehand knowledge of which services will be write-restricted.
· By default, the write-restricted service looses write access to a lot of resources it would normally have access to by virtue of its account and groups. Write access must be explicitly granted to the service SID, the logon SID, the write-restricted class, or Everyone to be possible.
While running your service as "Unrestricted" (see our previous post “Per-service SID”) allows you to protect your resources using the per-service SID, running your service as "Restricted" protects the system in the event your code would get compromised (how can that be? J). It is a measure of good citizenship: your code runs write-restricted and its impact on the system in case of an exploit is mitigated. Is it expensive? You bet it is. You have to determine all write accesses your code will need and make sure you explicitly grant that access to your service. Are there tools to do so? We don't know, please comment…
A built-in example
In Windows Vista, only a few services are natively provided as “write-restricted”. The
sc qsidtype MpsSvc
command will show you that the Windows Firewall service (MpsSvc, short for Microsoft Protection Service) is configured to be a “Restricted” service:
[SC] QueryServiceConfig2 SUCCESS
A quick inspection with a tool showing security tokens, like Process Explorer, will confirm that this service is indeed using a write-restricted token. The Windows Firewall service is hosted in a svchost.exe process running with the Local Service account and which also contains other services: Base Filtering Engine, Diagnostic Policy Service, Windows Media Center Service Launcher, Performance Logs & Alerts.
command will return
showing an explicit ACE granting full control to the MpsSvc service SID. This is used to protect this folder and its content, namely firewall logs. As the Windows Firewall service is a write-restricted service, the net result will be that except for this folder and its content, the service won’t be able to write anywhere else on the file system except places where Everyone can write (or that have an explicit write permission for NT AUTHORITY\WRITE RESTRICTED which we did not find. If you do, please share by posting a comment. Thank you).
The same reasoning was applied to the registry: the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy
key. Looking at its ACL shows inherited permissions granting full control to Administrators and System and read permission for Users on the key and its subkeys, full control for the owner of any subkey and explicitly grant full control for MpsSvc service on the key and its subkeys. As we’ll see in our next post, some subkeys here are used to apply network restrictions on services. Therefore, it is particularly interesting to protect those rules so that only the Windows Firewall service NT AUTHORITY\WRITE RESTRICTED, an Administrator or the System can modify or create them. Moreover, due to the use of a write-restricted token, the Windows Firewall service can only write in this part of the registry and nowhere else except on keys Everyone can write to (or that show an explicit write permission to NT AUTHORITY\WRITE RESTRICTED; so far, we don’t know any shipping with Windows Vista. If you find one please share with all of us by posting a comment. Thank you).