Fixing "LUA bugs", Part II
If (and only if) items #1 through #3 (a, b and c) from Fixing LUA bugs, Part I don’t allow your apps to work as normal user, then – and only then – move on to items #4 and #5, which are described in this article, along with their respective benefits and drawbacks.
#4: Loosen ACLs
The usual reason for LUA bugs is that the developers (and often, the testers) always ran as admin. They didn’t explicitly set out to require that the end-user run as admin, but things crept into the code that depended on admin access, such as writing to files in the root folder of the C: drive, in the app’s installation folder under %ProgramFiles%, or in %windir%. The app worked correctly until you ran it on your machine as a regular User. The app wasn’t designed to handle that scenario gracefully, and barfed. (See What is a LUA Bug…).
Option #4 is to change the Access Control List (ACL) on objects to grant your User the access that the program requires. Typically the objects that need tweaking will be in the registry or in the file system (if using NTFS). This must be done very carefully, though, and only after all of the more-preferred options have failed.
- App-specific resources only: ACL changes should only ever be considered on application-specific resources, not on OS-wide resources. While it might be OK to change the ACL on %ProgramFiles%\VendorX\AppX\DataFolder, you should never change the ACL on %SystemRoot%\System32 – to loosen or to tighten access. (See KB article 885409 for more information.)
- Not used by admins: Avoid changing ACLs on resources – particularly executables such as .exe and .dll files – that are ever used by administrators or services. Doing so increases the risk of elevation of privilege leading to compromise of the entire system. (Even so, the attack surface would remain far smaller than it would be with everything always running as admin.)
- Avoid binaries: Avoid changing ACLs on program code (e.g., exe, dll, or ocx files) if at all possible, to prevent malware from infecting or replacing them.
- Single non-admin user (ideal): Ideally, the resource should be one that is only ever accessed by a single non-admin user. If the resource is accessed by multiple non-admin users, there is increased risk of one user causing another user’s account to be compromised. As described above, if it is ever used by an admin user or a service, risks are increased further.
- Least additional privilege: You should grant the least amount of additional access to the smallest possible number of resources and to the smallest possible number of users in order to allow the app to work. Granting Full Control to Everyone on a big chunk of the file system or registry should never be necessary.
Granting the additional access only to the computer’s primary user is optimal, but that may be difficult to manage across a large number of systems when each computer has a different primary user (e.g., grant MARY the permissions on one system, STEVE on another, etc). If you can define a set of users who need to use the program, add them to a group and grant the access to that group.
Another alternative to consider is to grant access to the built-in INTERACTIVE pseudo-group. This will grant the additional access only to whoever is interactively logged on at the time, without also granting any additional remote access to the resource. Note that in a terminal server or Fast User Switching scenario there can be multiple simultaneous users on the computer with INTERACTIVE in their tokens.
Benefits of this approach:
Big return on the investment of your time – most of the LUA bugs that my colleagues and I have seen revolve around file and registry permissions. This approach will probably fix a larger share of your LUA bugs than any other approach.
Drawbacks to this approach:
- It’s #4 on the list for a reason. This approach allows otherwise-constrained users to change shared resources – for good or evil, and makes it easier for one user (or malware unintentionally run by that user) to affect others. If the affected user is an admin, the entire system can be compromised.
- As with items #3a and 3b, it is not easy, with today’s tools, to identify precisely which resources should be opened up and by how much. (More on this in upcoming posts.)
- It can be difficult to know for certain whether opening access to a resource will inadvertently expose an avenue for elevation of privilege, allowing system takeover.
#5: Run the one app with elevated privileges
As a last resort, after all else fails, consider running that one app with elevated groups and/or privileges. Some apps, for example, “address” their LUA bugs by explicitly checking for admin group membership on startup and displaying an error message insisting that you simply have to be an admin to use the program. This may be due to developer laziness, incompetence or arrogance (or all three), but these apps will be resistant to any other workarounds available to you.
Typically, this approach means running the app as admin. You could instead run the app elevated but less-than-full-admin – for example, as a member of Power Users or with a specific privilege such as SeLoadDriverPrivilege. Note, though, that with a little more work many of these other groups and privileges can still be used to take over an entire system.
Benefits of this approach:
It’s better than always running everything as admin. That’s it – that is the only benefit of this approach.
Drawbacks of this approach:
Running an app with elevated privileges exposes far more risk than any of the options described earlier. It becomes very difficult to defend the system against a malicious user or malicious software when there’s an app running as admin. A simple example: Run “Notepad” as admin, then choose File/Open – that dialog is now a little Explorer-like window that gives you full, admin-level access to the entire file system, and even the ability to launch programs as admin. That can be exploited by a malicious user, or by malware pumping keystrokes or window messages into the elevated program.
How to do it:
If you trust the user with the admin password or to otherwise make security and trust decisions:
- RunAs – see "RunAs" basic (and intermediate) topics and RunAs with Explorer for more information.
- MakeMeAdmin – see the original post and this follow-up. MakeMeAdmin is a batch file, so you can easily customize it to run something other than a command shell. You can also customize it to make the elevated context less than full-admin.
- PsExec and Process Explorer from SysInternals offer various RunAs-like options. See Mark’s blog post for more information.
- RunAsAdmin, an interesting open-source utility by Valery Pryamikov, a very smart Developer Security MVP. RunAsAdmin takes an approach a little like Windows Vista’s UAC, elevating the current user in place without requiring a password.
If you don’t trust the user with the admin password:
- PolicyMaker Application Security by DesktopStandard uses a Group Policy extension to configure rules for modifying process tokens. PMAS mitigates some of the drawbacks described above. For example, it can be configured so that child processes launched by a targeted app do not inherit its modified token, and can perform granular token modification, raising (or lowering) permissions, and/or adding (or removing) privileges.
- Protection Manager by Winternals (the for-profit side of SysInternals) uses a lightweight client-server application and a whitelist approach to block all untrusted applications – while also allowing applications that to have their process tokens and privileges elevated to that of an Administrator or reduced to that of a User (in cases where end users are non-Administrators or Administrators, respectively). Protection Manager also doesn’t allow a child process of an elevated app to run elevated unless it is also explicitly configured as an elevated app. Conversely, all process children of reduced privilege processes are reduced automatically (to also minimize security risk). Applications can be allowed, blocked, elevated, or reduced as specified by an administrator via Digital Signatures, Hashes, NTFS File Ownership, or Path.
Trying to "hide" the admin password:
The DesktopStandard and Winternals products determine in kernel-mode code whether, when and how to modify a process token. Passwords are not used and are therefore not at risk to exposure, and the modification decision cannot be interfered with by non-admins. By contrast, there are various tools available that perform RunAs-like operations with the admin account credentials encrypted (or sometimes just obfuscated). Even though this raises the bar and will stop some users from getting the admin creds, those passwords still have to be decrypted within the user’s security context, and so are exposed to a user with the right tools.
A frequently asked question is whether the RunAs.exe /savecred option would let one create a shortcut to run a single app as admin using a saved password and not requiring further password entry. There are several issues you should be aware of:
- The credentials are not tied to any one shortcut – once the creds have been saved they can be used to start any app
- While the password is securely encrypted with a user-specific key, it will still be decrypted in the user’s security context and at least briefly exposed
- The /savecred option is not available on XP Home Edition.
//TODO: Discuss my thoughts about the SRP/DropMyRights approach. (Bottom line: I dislike it.)
Much thanks for help and insight for this post goes to Eric Voskuil and Kevin Sullivan of DesktopStandard, and to Mark Russinovich and Wes Miller of Sysinternals/Winternals.