3

Background

I'm trying to understand more about the Mandatory Integrity Control system in Windows, and have been looking through the background processes that are running at High integrity on my laptop.

I've read through all the documentation that I can find on the integrity system, and my understanding is this: The integrity level of a newly started process should be (at most) the lower of the integrity level of the parent process and that of the executable file. If the process wants to elevate above that level, there should be a UAC prompt (assuming UAC is set to Always notify).

System Info

  • Windows 10 Pro 21H2 (build 19044.17066)
  • Secure Boot enabled
  • UAC set to Always notify (highest level on the slider).
  • PC is domain-joined. (Not sure if that would make any difference.)
  • My user account is in the local Administrators group.
  • Group policy settings (under Windows Settings > Security Settings > Local Policies > Security Options) are:
    • User Account Control: Admin Approval Mode for the built-in Administrator account
      • Value: Not Defined
    • User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop
      • Value: Disabled
    • User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode
      • Value: Prompt for consent on the secure desktop
    • User Account Control: Behavior of the elevation prompt for standard users
      • Value: Prompt for credentials
    • User Account Control: Detect application installations and prompt for elevation
      • Value: Enabled
    • User Account Control: Only elevate executables that are signed and validated
      • Value: Enabled
    • User Account Control: Only elevate UIAccess applications that are installed in secure locations
      • Value: Enabled
    • User Account Control: Run all administrators in Admin Approval Mode
      • Value: Enabled
    • User Account Control: Switch to the secure desktop when prompting for elevation
      • Value: Enabled
    • User Account Control: Virtualize file and registry write failures to per-user locations
      • Value: Enabled

Observation

I've found an example of an executable that seems to always run at High integrity (as reported by Process Explorer). It's an executable called SnagPriv.exe which is part of TechSmith Snagit 2019. This is normally started by the main Snagit process (Snagit32.exe, which itself runs at Medium integrity), and it runs as a background process. However, if I manually start SnagPriv.exe from a non-elevated (Medium integrity) command prompt, I get the same behavior - SnagPriv.exe runs at High integrity.

Executable info

icacls output:

icacls 'C:\Program Files\TechSmith\Snagit 2019\SnagPriv.exe'
C:\Program Files\TechSmith\Snagit 2019\SnagPriv.exe NT AUTHORITY\SYSTEM:(I)(F)
                                                    BUILTIN\Administrators:(I)(F)
                                                    BUILTIN\Users:(I)(RX)
                                                    APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)
                                                    APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX)

Successfully processed 1 files; Failed processing 0 files.

All of these ACEs are inherited from C:\Program Files. They are also all the same on Snagit32.exe, the executable that calls the one in question.

sigcheck output:

sigcheck64.exe -m 'C:\Program Files\TechSmith\Snagit 2019\SnagPriv.exe'

Sigcheck v2.82 - File version and signature viewer
Copyright (C) 2004-2021 Mark Russinovich
Sysinternals - www.sysinternals.com

c:\program files\techsmith\snagit 2019\SnagPriv.exe:
        Verified:       Signed
        Signing date:   8:17 AM 27/10/2018
        Publisher:      TechSmith Corporation
        Company:        TechSmith Corporation
        Description:    Snagit RPC Helper
        Product:        SnagPriv
        Prod version:   19.0.1.2448
        File version:   19.0.1.2448
        MachineType:    64-bit
        Manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"><requestedExecutionLevel level="asInvoker" uiAccess="true"></requestedExecutionLevel></requestedPrivileges></security></trustInfo><asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"><asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"><ms_windowsSettings:dpiAware xmlns:ms_windowsSettings="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</ms_windowsSettings:dpiAware></asmv3:windowsSettings></asmv3:application><ms_compatibility:compatibility xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" xmlns="urn:schemas-microsoft-com:compatibility.v1"><ms_compatibility:application xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1"><ms_compatibility:supportedOS xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"></ms_compatibility:supportedOS><ms_compatibility:supportedOS xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></ms_compatibility:supportedOS><ms_compatibility:supportedOS xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"></ms_compatibility:supportedOS></ms_compatibility:application></ms_compatibility:compatibility></asmv1:assembly>

Here's the manifest pretty-printed:

<asmv1:assembly manifestVersion="1.0"
    xmlns="urn:schemas-microsoft-com:asm.v1"
    xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
    xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <trustInfo
        xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges
                xmlns="urn:schemas-microsoft-com:asm.v3">
                <requestedExecutionLevel level="asInvoker" uiAccess="true"></requestedExecutionLevel>
            </requestedPrivileges>
        </security>
    </trustInfo>
    <asmv3:application
        xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
        <asmv3:windowsSettings
            xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <ms_windowsSettings:dpiAware
                xmlns:ms_windowsSettings="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM
            </ms_windowsSettings:dpiAware>
        </asmv3:windowsSettings>
    </asmv3:application>
    <ms_compatibility:compatibility
        xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1"
        xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <ms_compatibility:application
            xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1">
            <ms_compatibility:supportedOS
                xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}">
            </ms_compatibility:supportedOS>
            <ms_compatibility:supportedOS
                xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}">
            </ms_compatibility:supportedOS>
            <ms_compatibility:supportedOS
                xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}">
            </ms_compatibility:supportedOS>
        </ms_compatibility:application>
    </ms_compatibility:compatibility>
</asmv1:assembly>

My understanding of the above is:

  • The SnagPriv.exe executable has no integrity label, which means it should default to Medium. Note that if I add an integrity label of Low to the executable then it doesn't change the end result.
  • The executable is signed, but this should not cause the UAC prompt to be bypassed. (Even if it were signed by Microsoft, which it is not.)
  • The manifest does not request elevation. (And even if it did, the UAC prompt should not be bypassed.)

Observed Behavior

If I use Process Monitor to observe what happens when I manually start SnagPriv.exe from a Medium command prompt, I can see that it actually runs three times in succession. The first two times, it runs at Medium integrity (or Low if I add the explicit label to the executable). Then, a consent.exe process starts, and finishes straight away (without showing me a UAC prompt). Finally, SnagPriv.exe runs for a third time, now at High integrity. All three runs of SnagPriv.exe have my Medium command prompt as their parent process.

Possible explanations

Here are the possible explanations I can think of:

  • SnagPriv.exe is requesting elevation from some other "colluding" process that is already running at High integrity. (However I have checked and this behavior occurs even when there are no other processes running that are part of this application.)
  • The application has stored some sort of persistent access token that allows it to elevate. (Not sure if this is possible.)
  • Some sort of UAC bypass exploit is being done. (Seems highly unlikely, as this is a reputable application.)
  • My UAC settings are being ignored, or I have misunderstood what they mean. This would explain why consent.exe runs but doesn't show the prompt. (Note though that UAC seems to be working as expected other than this case.)
  • There is some mechanism that I'm not aware of for an executable (or signer) to be registered as not requiring a UAC prompt (e.g. in the registry somewhere). Obviously I would expect such a setting to be only modifiable from High integrity, but this could have been done at install time. (I would have run the installer elevated.)

Just to be clear, my question isn't about why this particular application needs to have a process running at High integrity. (I'm fairly sure this is legitimate, as it's a screen-capture app.) I'd just like to understand how it is able to do this, so that I can be on the lookout for malicious code that might use the same mechanism. I'm sure I'm just missing something obvious, but I have no idea what it is.

Does anyone know what I might be missing? Or are there any tools that I could use to better understand what's going on? I've tried Process Monitor and API Monitor, but they both return tons of output for the relevant processes, and I'm not sure what types of API calls I should be looking at to narrow it down.

2
  • 1
    Have you changed UAC mode to the highest mode? The default mode can be bypassed in various ways.
    – Robert
    Jun 6, 2022 at 11:07
  • @Robert Yes, this is in the "System Info" section of my question. Unless there's another mode selection somewhere else that I'm not aware of. Jun 6, 2022 at 17:30

1 Answer 1

5
        <requestedPrivileges
           xmlns="urn:schemas-microsoft-com:asm.v3">
           <requestedExecutionLevel level="asInvoker" uiAccess="true"></requestedExecutionLevel>
       </requestedPrivileges>

The relevant part is in here. Specifically, it's the uiAccess="true" part. I suspected I'd find that as soon as I saw the program name, and moreso once I saw the behavior described.

The purpose of the uiAccess attribute is to mark binaries which are intended to be able to operate as part of the user interface for all programs (typically this means capturing or injecting mouse and keyboard events, using accessibility and automation APIs, and so on). Because a process can't interact with another process of higher integrity, such programs must run as High integrity in order to not be locked out of interacting with elevated programs. Programs with the uiAccess flag specify to the operating system that they need this High integrity level in order to work correctly.

This is not the security hole in Windows' Mandatory Integrity Control that it might seem. First of all, the uiAccess=true flag is (by default) only respected on programs installed under the \Program Files\, \Program Files (x86)\, and \Windows\system32\ directories, all of which require Administrator-level access to write to. This behavior is controlled by the security policy you mentioned above, "User Account Control: Only elevate UIAccess applications that are installed in secure locations" (link contains Microsoft's documentation of this behavior).

Furthermore, regardless of that policy setting, the binary must be signed via the private key for a code signing certificate that is issued by a trusted certificate authority. As such, three things would have to go wrong for this to be an EoP vector:

  • Some non-malicious application, running elevated, would need to make a subdirectory of one of the above locations writable to unprivileged users (or else change the security policy). This happens sometimes (Steam used to and might still create a writable directory under \Program Files\) but it's rare. Note that it does need to be a non-malicious application; if a malicious application could make the change, it wouldn't need to use this vector to elevate privileges.
  • A trusted code signing cert is issued to an untrusted developer, or a trusted developer's code signing private key is compromised, or an Administrator user is tricked into installing a malicious CA certificate to the device Trusted Root Certification Authorities store.
  • A malicious but unelevated process places the malicious signed executable in the writable trusted location (or the user is tricked into doing so, somehow) and then the executable is executed.

Note that even in this case, it only works if the user is a member of the Administrators group (and using Admin Approval Mode in UAC, otherwise all programs are elevated by default). If the user is not a member of the Administrators group, then attempting to launch the process will launch it as the normal user (if, as seen here, level="asInvoker" is specified and the process is not requested to start elevated) or else (if the user or executable manifest requests that the process start elevated) a UAC prompt to run as some other (Administrator) user will be shown. The behavior of the UAC prompt, if elevation is requested, will depend on the "User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop" security policy (and, if disabled, falls back to the standard UAC policies). In other words, uiAccess can never elevate a program for a non-Administrator - merely make it possible for programs without access to the Secure Desktop to see its own UAC prompt - and for an Administrator, it only provides a way to automatically gain some privileges without needing the user to approve a UAC prompt, if the program was installed in a way that already requires administrative permissions.

3
  • Thank you for this incredibly detailed and clear explanation of not only "what is happening" but also "why it's done like this"! I had read about uiAccess, but had missed the fact that it does more than just allow programs to disable the secure desktop (and in fact that part is only relevant for standard users anyway). Jun 7, 2022 at 20:46
  • 1
    As for the ways this could be an EoP vector, I assume it would also be possible for a non-malicious (but buggy) process that accepts input from unprivileged users through any channel (e.g. IPC or networking) to be exploited to gain privileges. Although DEP and code-signing requirements would prevent some of the most straightforward attacks like buffer overflow. So I guess if you wanted to know all the things that can run at high integrity on your system without prompting you, you'd scan those "secure locations" for executables with uiAccess="true" in their manifests. Jun 7, 2022 at 20:58
  • 1
    Yes, vulnerabilities in UIAccess apps are definitely also a threat, though that's true of all software that runs elevated (and indeed all software that isn't tightly sandboxed, since most malware doesn't actually need admin privileges these days). Anyhow, you're welcome for the explanation, and you're correct that scanning for signed and trusted-location UIAccess executables is part of enumerating attack surface for local EoP.
    – CBHacking
    Jun 7, 2022 at 23:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .