All on Internet

Tuesday, November 21, 2006

Fixing LUA(Limited User Account) bugs

First, what is "LUA"?

"LUA" is an acronym that variously refers to "Limited User Account", "Least-privileged User Account", "Least User Access", and probably several other clumsy phrases that ultimately indicate a computer user account that cannot make changes that affect other users of the system or the operating system itself. In Windows, these are typically members of the built-in "Users" group; they are explicitly not members of powerful groups such as "Administrators", Power Users", or "Backup Operators", and do not hold elevated privileges such as "Load and unload device drivers," "Take ownership of files or other objects," or "Act as part of the operating system".

A "LUA bug," then, refers to an application -- or a feature of an application -- that works correctly when run with elevated privileges but fails to work for a LUA user, and where there is no technical or business reason for requiring elevated privileges. A common example is when an application saves its runtime settings to a registry key under HKEY_LOCAL_MACHINE (which is read-only to LUA users), instead of to HKEY_CURRENT_USER.

Windows doesn't allow LUA users to change the system time. That is not a LUA bug, because changing the system time has security implications with respect to auditing and to the Kerberos protocol. The fact that Windows XP doesn't allow LUA users to change the time zone is arguably a LUA bug, as is the fact that double-clicking the clock in the taskbar's notification area gives you an error message instead of a read-only view of the Date&Time applet. (Note 1: Vista is heavily focused on a more seamless LUA experience -- see the UAC blog for more info -- and the Date&Time applet is a primary target for an upgraded experience. Note 2: I wrote an earlier post about how to grant a Windows XP user the ability to change the date, time and/or time zone.)

By far, the majority of LUA bugs are due to registry and file system access. A program might try to save its settings into its installation folder under %ProgramFiles%, or it might try to open a key under HKLM for "All-Access" even if it only ever needs Read access. However, there are other types of LUA bugs: attempting to start or stop a service, load a device driver, access hardware resources directly, create or manage file shares, or even explicitly check whether the current user is a member of the Administrators group.

At the core, there are always one or more low-level operations ("API calls") that succeed when performed as admin but that fail when performed as LUA. You can see some of these yourself using tools such as SysInternals' Regmon and Filemon. However, is every one of these a real LUA bug? The answer is that it depends on how the application responds to the failure. The responses I have seen can be categorized in one of three ways:

"Fire and forget": The application invokes the operation, doesn't check the result, but doesn't depend on the operation having succeeded in order to continue working correctly. This is not a LUA bug.

"Gracefully degrade": The application invokes the operation, checks whether it succeeded, and handles failure in an appropriate way. This is not a LUA bug.

"True LUA bug": The application invokes the operation, assumes it succeeded, and depends on the operation having succeeded in order to continue working correctly. A variation on this is that the app checks whether the operation succeeded, but handles the failure inappropriately, such as by displaying an error message and falling over dead.
If you've ever monitored a GUI app running as LUA with Regmon, you've probably come across an example that could be categorized as fire-and-forget: a failed attempt to open HKLM \ System \ CurrentControlSet \ Control \ MediaProperties \ PrivateProperties \ Joystick \ Winmm for All-Access. This occurs during initialization of the joystick subsystem for the process. The specific operation fails, but it does not impact the correct behavior of your application. However, I have seen "guidance" on the web (no doubt from people misinterpreting Regmon output) claiming that to fix some particular application you need to grant the user full access to this key. No! It's not a true LUA bug. You should never need to change permissions on this key!

Before you go making wholesale changes to security settings, you should verify that you're remediating a true LUA bug and not just a phantom, and that there aren't better ways that don't increase exposure. More on that in upcoming posts.



You have an application that you – or your users – need to run. It’s a normal app – it isn’t designed to perform system administration of your computer, but for some reason, it doesn’t work correctly unless it’s run from an account that has administrator-level access (see “What is a "LUA Bug"? (And what isn't a LUA bug?)”. But you don’t want your users running as admin. What to do?



The “workaround” most frequently chosen is simply to add the user to the Administrators group. Sometimes this approach is not decided by the IT department, but by some “helpful” HelpDesk technician: “Let’s see whether this fixes the problem.” The technician forgets to remove you from the Admins group, inevitably leading to another HelpDesk call within a few weeks: “HelpDesk, why is my computer running so slowly, and why are all these porn ads popping up whenever I log on?” (Answer: Because you’ve been running as admin!) Let’s just call this “workaround” a non-starter and not give it any further consideration.



Other common but sub-optimal workarounds are: 1) run the one program as administrator, or 2) run the program as a regular user, but after granting Everyone “Full Control” over the program’s installation folder and all of its registry keys under HKEY_LOCAL_MACHINE, and to all of HKEY_CLASSES_ROOT. Oh, and while we’re at it, grant the user the “Debug”, “Take ownership” and “Act as part of the operating system” privileges. These are seriously high-risk ways to get the program to run, and should be avoided.



So what do you do? In this mini-series of posts, I’ll lay out a systematic approach for working around LUA bugs that minimizes exposure. I’ll discuss approaches from most-preferred to least-preferred, with some of the pros and cons of each. By the way, while this guidance is targeted primarily to Windows XP, it will also work on Windows Vista.





#1: It is a bug – treat it like one and make the developers fix it!



This is the most preferred approach. If there is no legitimate business or technical reason for the app to require admin privileges, then failure of the app to work for a regular user account is a serious bug that compromises system security, stability and manageability. (Note: if the development team says something like “It’s mission-critical, so it has to run as admin”, or “it writes to HKEY_LOCAL_MACHINE, so it has to run as admin”, the correct response from you is, “You’re talking nonsense. Fix the bug!”)



Benefits of this approach:

Once it is fixed this way, you don’t need to carry forward any shims, tweaks or workarounds.
Developers may learn from the experience, and stop creating new LUA bugs. (Note: Developers running as admin are the #1 cause of LUA bugs!)


There are some drawbacks, though:

The expense in time and/or money may be prohibitive, particularly if you have limited resources and a lot of apps to fix. You have to consider the possibility of the app having to be rearchitected, and the possibility of new bugs being introduced in the process.
The developers and/or the source code may not be available. It may be 3rd party code from a company that no longer exists. The developers may be in rehab. Or jail. Or working for your competitor. Or they may be working on something “more important”.




#2: Application Compatibility Toolkit



Use the LUA Mode shims of the Application Compatibility Toolkit (ACT). (File and Registry Virtualization is the equivalent solution built into Windows Vista.)



The LUA Mode shims detect attempts to write to system-wide locations in the file system and registry and silently redirect them to per-user locations.



Benefits of this approach:

It is easy to implement


Drawbacks:

The LUA Mode shims on XP often do not work (Vista’s Virtualization is a complete rewrite and will have much higher compatibility marks than XP’s ACT LUA Modes.)
The added complexity of the resulting underlying operations can make your troubleshooting more complicated when things don’t work.




The next 3 items (3a, 3b and 3c) are system changes that solve different specific issues, but share the common feature of not granting any elevated access to system-wide resources.





#3a: Copy specific HKCR keys to HKCU\Software\Classes



(Registry notations used here:

HKLM = HKEY_LOCAL_MACHINE;

HKCR = HKEY_CLASSES_ROOT;

HKCU = HKEY_CURRENT_USER)



Some background: Prior to Windows 2000, HKCR was just a symbolic link to HKLM\Software\Classes, which only Administrators can write to. In other words, operations performed on HKCR\.txt would actually occur in HKLM\Software\Classes\.txt. Windows 2000 introduced per-user registration data, so now HKCR is a merged view of HKLM\Software\Classes and HKCU\Software\Classes (which the user can write to). If a key exists in the latter, it takes precedence. So now an operation on HKCR\.txt will occur in HKCU\Software\Classes\.txt if that key already exists, otherwise it will occur in HKLM\Software\Classes\.txt as it had in the past.



The issue to fix: A number of applications write to HKCR at runtime to “reinforce” their file associations, COM registration data, etc., and raise an error if the write fails, even if the data they want to write is already there. The same data is written every time the app runs. If that same registration data were stored in HKCU\Software\Classes, then the write operations would succeed, without changing program behavior.



How to fix it: First you must identify the keys under HKCR that the application is trying to write to. (How to do that will be covered in later posts.) Export those keys to one or more .reg files (in Regedit, use File/Export, Selected branch). Using a text editor, replace all instances of

[HKEY_CLASSES_ROOT\

with

[HKEY_CURRENT_USER\Software\Classes\

and save your changes. Import the edited .reg file into the registry of the user who needs to run the program.



Benefits of this approach:

This fixes issues where applications perform operations in HKCR that should have been done only during installation.
This approach is better than loosening access control on system-wide resources under HKCR (HKLM). Malware overwriting keys under HKCU will not affect operating system components or other users of the computer.


Drawbacks:

It is not easy, with today’s tools, to identify HKCR writes as the source of LUA bugs, and exactly which keys are involved. (More on this in upcoming posts.)




#3b: IniFileMapping



Background:



Back in the days of Windows 3.x, before there was the Registry that we know and love, the OS and applications stored configuration and preference data to .ini (initialization) files, such as win.ini. Windows did and still does offer API-level support for .ini files via the “Profile” APIs (e.g., WritePrivateProfileString). Many apps (including some Windows applets) still use these APIs to try to write to .ini-formatted files, often in folders where Users are not supposed to write.



Windows NT 3.1 encouraged the migration from .ini files to the more scalable and manageable Registry, and provided a means for automatically redirecting .ini file reads and writes to registry keys. The internal implementation of the “Profile” APIs was augmented to use mappings found under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\. If a mapping for a .ini file is not found under that key, then the operation is performed in the file system as before.



The issue to fix: If access to an .ini-formatted file – via the “Profile” APIs – is the cause of a LUA bug, it can be remediated by adding a key under the IniFileMapping key to redirect access to HKCU. Note that IniFileMapping is under HKLM and requires administrative privileges to configure. The config specifics are described in the documentation for the “Profile” APIs, such as WritePrivateProfileString.



Benefits of this approach:

This approach is better than loosening access control on system-wide resources in the file system. Malware overwriting keys under HKCU will not affect operating system components or other users of the computer.


Drawbacks:

It is not easy, with today’s tools, to identify .ini-file access as the source of LUA bugs. (More on this in upcoming posts.)




#3c: SafeDisc



A number of games depend on the “secdrv” device driver, also known as “SafeDisc”, from Macrovision. The secdrv driver that ships with Windows XP is a demand-start driver, which users are not allowed to stop and start, resulting in errors when accessed by programs. There is an update, available from Microsoft and from Macrovision that configures the driver to be loaded when the system starts so that the user does not need to start it. This change allows some games to work correctly for a non-admin user.



(Note that as of this writing, the Microsoft download page for this update says that “[t]his software will not alter or patch any component on your system, it will only change the startup state of the system component…” This is actually not true – it installs an updated driver.)



Benefits: Easy to implement, and no ACL changes to systemwide resources.



Drawbacks: None, really.





Coming up in Part 2:

#4: Loosening specific ACLs, and

#5: Running the one app as admin



#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.



Constraints:

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.

No comments: