Today We Learn About Elevation, Integrity Levels, and UIAccess

With the App-V MVPs busy at the MVP Summit this week, I’ll offer up this rather long post about elevation, starting with some fairly well known basics and advancing into the absurd detail.

Applications sometimes do things that cause UAC prompts to qualify a process to increase its security settings or level. Most enterprise policies, and Microsoft recommended practices, restrict most users from knowing accounts and passwords that have administrative access, preventing such applications from ever being deployed natively. When natively deployed, these applications would cause UAC prompts requiring the end user to know credentials for an account with administrative access, which is unacceptable.

The biggest impact that App-V can have on these processes is that while running under App-V, elevation might no longer be necessary. Because App-V redirects writes to most system file and registry locations (any file and registry locations if we set up the App-V package appropriately) to safe locations that only affect this particular user when running processes from this package, we can often get such applications to work correctly without the user seeing a UAC prompt or having to have administrative credentials.

Often, when the prompt was due to an attempt at write access to protected locations, App-V solves the problem automatically thanks to the redirection to safe locations. And when the prompt is due to vendor requested elevation using a manifest, we can sometimes work around it.

I have been working with a well-known Software Vendor that wants to support their customers that use App-V. In their case, which is quite rare, App-V had the opposite effect. This work has both forced me and enabled me to learn more about things of which I had only little knowledge of; things that turn out to be a great value to those who deal with deploying applications.

Part 1: How do I Elevate, Let Me Count the Ways

The following list cover the major ways that the elevation level of a process is set. It is possible that there are other methods to alter the process elevation level, but for those you might be on your own.

By default processes start using the security context, and therefore the elevation level of the process that started it. Most often, this means the user’s explorer.exe shell which will have started the process, via start menu shortcut, file type association (FTA), or clicking on the exe. The items in the list below (not presented in a specific order) may override this level.

  • The user may start a process using a right-click “Run as administrator” on an lnk file, exe file, or file with an FTA to an exe.
  • The user may click on a lnk or exe file with a compatibility property attribute set to RunAsAdmin. (Seen as right-click, properties on the compatibility tab of the property sheet).
  • The file may have an internal or external manifest file requesting a higher, or lower, elevation level and/or UiAccess setting.
  • There may be GPO or 3rd party tools setting the level of any process, typically by process name.
  • During execution, the process may attempt a write access to a resource such as HKLM or protected file areas, triggering a UAC prompt. If the user accepts the prompt (possibly needing appropriate admin credentials), the elevation level will be increased.

The elevation level of a process is categorized sometimes into buckets known as “Integrity Levels”. This nice post explains the integrity levels quite well, but we really need to understand the underlying elevation level to be successful in manipulating apps and unnecessary UAC prompts. But go read that first, and come back. This post will still be here.

Part 2: About the Application Manifest

Applications that are based on Microsoft .Net may have a manifest file. When not present, a default equivalent is used. Older “Win32” style applications do not use them. An application’s manifest consists of an XML file that is the basis of controlling the security context of an application. A definition of the capabilities and format for the manifest don’t seem well defined as they are defined in different portions, such as on MSDN here. While there are a lot of possibilities, I generally find one or two things of interest to me in manifest files:

  • A Trust Info
  • OS Version Compatibility

This manifest file is typically included as a resource file within the application’s executable “PE” formatted file. It may also exist as an external file that is in the same folder as this executable and uses the same name with a “.config” extension (as in “foo.exe” using “foo.exe.config”).

When in doubt if an internal or external manifest is being used, this old post contains a script that might help. An external config file will override the default manifest used when the application does not have an internal manifest. By default, an internal manifest file wins over an external config, but this behavior may be changed using a registry setting of:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\PreferExternalManifest

As a DWORD set to a value of 1.  I don’t find administrators willing to use this setting, possibly because they don’t know how to justify it, but I do not find it a problem at all for security as long as users don’t have access to write to the Program Files area where you would put these external config files.

 

OS Version Compatibility

By default, applications do not declare specific OS Compatibility list in the manifest. If they do, they are doing this using feature based GUIDs that indicate which operating system they work with, but in the end they are basically used as an OS indication. Not only does the vendor declare that they will work on that OS, they also declare that the Right click application property to set the configuration to run as if on a given OS should work. While this might be good way to declare that the app won’t work on an older OS, it is a pain because, as you can see in the link above that predated Windows 10, you don’t know what the future OS Version GUIDs will be (even after the public release of Windows 10 it took a couple of weeks before the new GUID was documented). Fortunately, if the vendor decided to add these settings and got it wrong you do have an opportunity to fix it with an external manifest (but only if you are willing to set the SideBySide\PreferExternalManifest setting system-wide.

TrustInfo

Trustinfo contains two interesting settings that affect UAC elevation and Elevation prompts, Level and UIAccess. Surely you have seen things such as:

<requestedExecutionLevel      level=”requireAdministrator”      uiAccess=”false”/>

But what are these?

We will get to execution levels later on. The level setting may be one of three things:

  • runAsInvoker meaning just use the (security) execution level of the caller. This is the default when no manifest is specified or the level is not specified in the manifest.
  • highestAvailable means that a UAC prompt should be given for elevation of the execution level, but if declined then the app will run using the level of the caller.
  • requireAdministrator means that a UAC prompt should be given for elevation of the execution level, but if declined that app will not run.

By the way, if the level of a process is elevated due to the setting, the process is terminated and automatically restarted with the higher execution level.

The UIAccess setting is either true or false, and until recently I didn’t understand what it did. When set to true, it allows an application access to other application windows. This is needed for user interface automation tools, for example, or for UI automation and screen capture utilities. These apps don’t need full administrator access to the system, and Microsoft treats this as a minor elevation of the execution level. Under certain conditions (which is where I found myself researching into for the vendor problem with App-V), this elevation is allowed to occur without a UAC prompt. We’ll talk more about these “certain conditions” later on in the post.

Part 3: About Elevation Level Detection

Ultimately, the security level is a number, with a higher number having more security privileges.   If you want to see what this level is for a process then the Microsoft SysInternals Process Explorer is your friend. Right click on a process and select properties (or just double click on the process) and select the security tab. In the “Group” window, select the entry (about 7th on the list) that starts with “Mandatory Label\” and Flags value of “Integrity”. The next text should say something like “Medium Mandatory Level” or “High Mandatory Level”. The image below is that of a normal cmd process that has not been elevated.

When you click on the line starting with “Mandatory Label/”, you will see the Group SID displayed just below the Group box. This is the SID String in the form “S-1-16-xxxx”. As described in Windows Integrity Mechanism Design, we can understand what these levels and values mean:

These Mandatory Level security display strings are based on the elevation level value, mapping ranges of the levels into the descriptive names:

Low High Label Notes
0 0 Untrusted Used for anonymous logons
1 4096 Low Things like Internet Explorer
4097 8192 Medium Normal users and administrators normally starting a process
8193 12288 High RunAsAdmin processes, for example
12289 16384 System System Processes

Processes are normally started at the highest security level of their range, so any elevation, such as the UIAccess elevation, will cause it to fall in the next higher range.

For example, a request to run as an administrator, either via right-click “RunAsAdministrator”, manifest file elevation, or file/registry triggered UAC prompt elevation, increases the level by 0x1000 (4096 decimal).  The image below is of a cmd process that was elevated using a right-click “RunAsAdministrator”.

A successful UIAccess=”true” elevation only increases the current elevation by 10.

 

Part 4: App-V Preventing UAC prompts on apps that Elevate by Writing to Protected Areas

Processes that elevate due to attempts to write to protected system areas, are usually easy to detect when natively installed. When run by a standard user, these apps generate the UAC prompt when running, but not necessarily when the app is first started.

These applications generally work without prompting when you package and deliver them using App-V. This is because App-V is intercepting these write attempts and redirecting them to user and package specific “safe” locations. When we were installing these apps to the PVAD (Primary Virtual Application Directory), no special action is required when sequencing these apps, it just solves it. Because we now usually install using “VFS”, you just need to check the “Allow full writes to the VFS” checkbox on the advanced tab of the sequencer. Just keep in mind that executable components, like exe or dll files, may not be written/redirected for safety even with this checkbox. This means that auto-updaters must be disabled, but IT generally prefers it that way anyway.

But sometimes the default sequencing doesn’t prevent the problem and you get a UAC prompt when the app tries to write. Usually this means that the path being written to was not covered by the folder/file structure of the package, and the write access is being attempted natively. When this happens, you should use ProcessMonitor to detect the attempted location of the write. Then you can update the package to add the folder or registry key to the package to ensure coverage. Just make sure to consider the marking the folder/key, which you probably want marked as MergeWithLocal.

Part 5: App-V and Overriding Manifest Elevation Level Requests

There are three cases to consider when working with manifests that request elevation. These techniques are successful, as long as the application didn’t require elevation for purposes other than to write to protected areas.

Overriding RunAsAdministrator without messing with Manifests.

The most common fix for applications virtualized with App-V is to override a manifest requested elevation to highestAvailable or requireAdministrator is to override it using an environment variable. By setting __COMPAT_LAYER to RunAsInvoker, you effetely tell the OS to ignore the level parameter of the manifest.

But for this to work, you cannot simply set that as an environment variable in your package, because it must be set before the application starts. So the typical solution if to add a cmd file inside the package. If the application is foo.exe, we would make a foo.cmd file and place it next to foo.exe. The contents of foo.cmd would be:

@Echo Off

Set __COMPAT_LAYER=RunAsInvoker

Start foo.exe

We then edit the shortcut to foo.exe and make the target:

cmd.exe /C [path]\foo.cmd

We make sure the shortcut uses foo.exe for the icon so it looks right also. The user may see a flash of the CMD dialog box, but it disappears very quickly.

Overriding RunAsAdministrator by messing with Manifests

Using an external manifest “(foo.exe.config”) is quite an easy fix for applications that do not have an internal manifest. It also solves applications with internal manifests, but only if you are willing to change the setting for which wins to the external.

If the application already has an external manifest file, you can just edit that one. Otherwise you can create your own as follows:

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>

<assembly xmlns=”urn:schemas-microsoft-com:asm.v1″ manifestVersion=”1.0″>

<assemblyIdentity version=”1.0.0.0″ name=”foo.exe”/>

<trustInfo xmlns=”urn:schemas-microsoft-com:asm.v2″>

<security>

<requestedPrivileges xmlns=”urn:schemas-microsoft-com:asm.v3″>

<requestedExecutionLevel level=”asInvoker” uiAccess=”false”/>

</requestedPrivileges>

</security>

</trustInfo>

</assembly>

Just replace the name and version of the assembly (right click on the foo.exe file, select properties, then click on the details tab to get the version number. If you get it wrong it’s OK) in the sample above. When sequencing, place this file in the same folder as the executable using the same name with an additional .config extension.

Overriding by using AppCompat Toolkit Shims

This article is already far too long to dive into this topic in detail. But creating a shim is another option with App-V. An AppCompat shim can override elevation or emulate OS versions, or add its own file or registry redirection. This not only can solve UAC issues, but also help redirect important user-app data into the user’s home drive or roaming profile. To use a shim with App-V, you must both apply the shim while in the sequencer, and apply the shim natively at the client. Fortunately, you can use an AddPackage script to install the shim (sdbinst.exe {[AppVPackageRoot}]\..\Scripts\foo.sdb). Google “Microsoft Chis Jackson and Shim” for some excellent videos and tutorials on creating shims.

Part 6: App-V and Manifest using UIAccess=True

As mentioned before, UIAccess=”true” allows, under certain circumstances, for a process to self-elevate a minor amount (0x10 or decimal 16) without a UAC prompt. There are various descriptions of the requirements, some of which are misleading (and hence my involvement with the ISV). The best description that I have found is shown below, which is from this TechNet reference.

UIA programs must be digitally signed because they must be able to respond to prompts regarding security issues, such as the UAC elevation prompt. By default, UIA programs are run only from the following protected paths:

  • …\Program Files, including subfolders
  • …\Program Files (x86), including subfolders for 64-bit versions of Windows
  • …\Windows\System32

To check if UIAccess=”true” is happening due to an internal manifest, check a native installation of the application using an elevated Microsoft ProcessExplorer (as shown in Part 3). Assuming the process started as a normal process, you would see a SID of S-1-16-8208 (8192 + 16).

“ProgramData\App-V\[Guid1]\[Guid2]\Root\VFS\ProgramFilesX86\Vendor\foo.exe”

“ProgramData\Microsoft\App-V\Client\Integration\[Guid1\ Root\VFS\ProgramFilesX86\Vendor\foo.exe”

This fails to meet the requirements of the protected paths listed above. Note that several other references fail to list the folders above and generically say things like “a folder that only Administrators have write access to”.
Because it fails to meet the requirements, this leads to a UAC prompt to the user, possibly preventing the UIAccess elevation, which is likely needed by the app.

One solution to this problem is to add a cmd file to the package:

@Echo Off

CD %ProgramFiles(x86)%\Vendor

Start foo.exe

While monitoring you drop this file in the package and create a shortcut to it. Edit the properties of the shortcut to foo.exe and make the target “cmd.exe /v C:\Program Files\Vendor\foo.cmd”.

Now when foo.exe starts, it will be referenced as C:\Program Files\vendor\foo.exe and seems to pass the path test.

(NOTE: if you just make the shortcut the cmd file it will start the cmd file outside of virtual environment, even when App-V adds the /appvve to the actual published shortcut line. We need it to run inside the virtual environment, and using cmd.exe solves this problem).

The ISV in this case had additional complications. First, the app contained two program shortcuts to different programs, and the process that had the UIAccess=”true” manifest was a third process started by either main program (if not already running). These main programs located the executable by using the current working directory, so without changing the shortcuts there would be a UAC prompt. It the user knew an admin password it worked fine, but without it the third process did not have permissions to do what it was designed for. Changing the two shortcuts caused the third process to start in the “correct” folder and pass the test and receive the additional access permissions without prompting..

Now if the main processes had used a registry based reference, instead of the shortcut/cmd trick, we would have had to dynamically stuff the reference we wanted into the virtual registry at runtime to prevent App-V from tokenizing it for us.

Thanks to Mike K for the lead on some references on this post.

By Tim Mangan

Tim is a Microsoft MVP, and a Citrix CTP Fellow. He is an expert in App-V and MSIX.