By: Shiran Grinberg
User Account Control, commonly abbreviated UAC, is a Windows security component introduced in Windows Vista and Windows Server 2008. UAC restricts processes’ access to admin-level (privileged) resources and operations as much as possible, unless they are explicitly granted by the user.
Figure 1: UAC prompt prompting the user to explicitly grant admin privileges to a program
For decades now, it has been customary for operating systems to differentiate between administrative users (also known as superusers, root or supervisors), capable of committing vast, system-wide changes – and standard users, that will mostly use the machine to perform work, without altering it in a substantial manner. This separation enforces the Principle of Least Privilege (PoLP), according to which processes, programs and users must be able to access only the minimal array of resources required for their legitimate operation at any given point.
However, early Microsoft PC operating systems did not employ this principle – in regards to user privileges, at least. In the first versions of Windows, for example, all applications had privileges equivalent to those of the OS itself!
This all came to an end with the introduction of Windows NT, as Microsoft finally created multiple account-security levels – separating admins from normal users. But users were still encouraged to use the built-in Administrator account, and many programs were already developed to run in the security context of an admin – relying on high-level privileges to function (often unnecessarily or unintentionally).
UAC’s goal was to bridge this gap – limiting access to high-privilege resources while striving not to compromise software functionality, legacy support and user-experience.
As for the user, UAC is pretty straightforward. When a program or process needs to escalate its privileges – meaning it requires administrator access for a certain operation – the user will be prompted for consent. If the current user is a standard user as described above, admin credentials will also be required to proceed.
An exception to UAC’s user consent rule is the relationship between parent and child processes. Child processes may inherit their parent’s access status, granting them automatic access to high-level operations, as will be elaborated in further detail below.
UAC has 4 different security-level configurations:
When a user successfully logs on to a Windows machine, the OS creates an access token, which is an object depicting the identity and privileges of the user. This token is attached to the initial process created in the user session, and will be inherited by child processes running in the user session.
Whenever a process tries to perform privileged system tasks, or to interact with securable objects (objects with a security descriptor, loosely meaning an access control policy), the OS will inspect its token to verify its integrity level.
But what if a process is trying to do something out of the security context set in its attached token? When this happens, the user may choose to escalate its privileges, by providing it with an admin-level token. Normally, all programs will run with a standard access token – even if it’s an admin user session. When an admin-level token is required, UAC will prompt the user for action. If the current user is an admin, a consent prompt will appear, asking him to allow the program in question to make changes to the machine. If the user is not an admin, a credential prompt will appear, asking him to provide admin credentials.
It’s worth mentioning that in its default mode, UAC will allow certain programs to auto-elevate their privileges without prompting the user for consent. These programs are Windows Executables – certain executables that are shipped with the OS, signed by the Windows publisher, and located in protected directories that standard users can’t modify. The logic behind auto-elevation is that integral executables shipped with the OS are safe, and prompting the user to consent to elevate their privileges is a nuisance.
Bear in mind that elevation requires admin privileges – standard users cannot grant programs high-level privileges. Yet in Enterprise environments, the vast majority of users will not have admin privileges, which may break the functionality of non-UAC-compliant applications. This is most common when legacy applications are attempting to write to a protected folder (such as %ProgramFiles%) or edit some registry values. To avoid this, Windows hands the program its own virtualized version of the required resource, which is maintained in the user profile. This way, the app may continue to function without compromising high-privilege resources.
Some actions that require privilege escalation are:
On surface level, UAC seems like a pretty good defense mechanism against malicious activity: it negates malwares’ ability to exploit high-integrity resources and alter the state of the machine, and polices the former no-man’s-land of user privileges. Yet over the decade or so since its introduction, countless UAC bypass methods and backdoors (MITRE T1548.002: Bypass User Access Control) were discovered – enabling adversaries to gain admin privileges without the victim’s consent. Some were patched but many still work. In fact, the open-source project UACME implements dozens such bypasses, of which a whopping 21 are yet to be fixed.
In Microsoft’s defense, UAC was not supposed to be a malware-security measure per se, but rather a functionality tool – designed to prevent oblivious users and ill-written programs from compromising an endpoint’s state. As we’ll see below, many of the UAC bypasses rely on design choices aimed at improving functionality and user-experience, at the cost of malware-security. Nevertheless, one could argue that the component may give users a false sense of security, impairing their judgement in regards to the programs they choose to download and execute.
Bypass methods could be categorized into two main varieties. The rest of this chapter will discuss these methods, and then we’ll demonstrate their usage in practice.
As discussed above, UAC allows certain Windows Executables to auto-elevate their privileges when an administrator is logged in. This is mainly to streamline the user experience and avoid excessive elevation prompts in the seemingly safe environment of executables shipped with the OS.
Alas, adversaries may exploit this caveat and the mechanisms enabling it to trick the OS into auto-elevating malicious processes.
Remember how processes may inherit their parent’s access status or token? Attackers can exploit this feature by tricking a high-integrity process into spawning their malicious code. One way to implement this is by DLL Hijacking. The hacker will inject an auto-elevating process with a malicious DLL file. Once the DLL is running and attempting to perform high-privilege tasks, UAC will allow it – as it is running under an auto-elevating process.
But how can the DLL be injected in the first place? One common way is to exploit the way programs load DLL libraries (MITRE T1574.001: DLL Search Order Hijacking). When a program needs to load a certain DLL, it will look for it in several locations, including: the registry (in case its path is stored as a registry value), the System directory, the Windows directory and the current directory. Adversaries may supply a malicious DLL instead of the original one and trick the program into executing it. But, as mentioned before, writing to these directories requires elevated privileges!
Unfortunately, ample workarounds are available. For one, the Windows Update Standalone Installer (wusa.exe) can be used to unpack CAB files into secure directories. WUSA can do that because – you guessed it – it’s an auto-elevating executable. Furthermore, the IFileOperation COM object can be used to move the DLL into the desired protected directory. This object relies on the Process Status API (PSAPI) to discern the security context in which it is running. But apparently a process may access its own handle and modify the flag PSAPI uses to assess its integrity level! So, the attack flow may be as follows:
Figure 2: DLL Injection bypass possible attack flow
There are currently at least 5 known unfixed DLL Hijacking UAC bypasses.
In a similar manner to how DLL searching can be exploited to inject malicious DLLs into auto-elevating executables, registry values could be tampered with to run malicious code (MITRE T1112: Modify Registry). For instance, it was discovered that when the fodhelper.exe Windows executable is instantiated, it looks for several non-existent registry values in the user-hive. And not just any values – but strings representing commands for execution! The relevant keys are:
Bear in mind that the user-hive registry values only require standard privileges to be edited, but the command will run in the context of an auto-elevating process. There are currently at least 5 known unfixed key manipulation UAC bypasses.
Instead of bypassing UAC by exploiting auto-elevation mechanisms, some exploits allow adversaries to disable UAC, either altogether or for a certain user or session. One famous vulnerability of this variety is CVE-2019-19894.
The exploit relies on a vulnerability in EasyInstall, also known as IXP, which is a remote desktop management tool used for managing endpoints and installing software over large networks. Usually a central EasyInstall server will control agents installed on network endpoints.
In the affected versions, the EasyInstall agent runs with admin privileges, but some of its folders were not write-protected. Authenticated adversaries could modify the software’s files and potentially compromise the victim machine. In particular, the configuration file “IXPAS.IXP” specified whether the agent should enable or disable UAC. Because the folders were not write-protected, the file could be replaced with a modified version flagging the agent to disable UAC. Upon rebooting the computer, UAC will be shut-down for all users until the machine was rebooted once again.
In this demonstration we will show two ways to bypass a victim Windows machine’s UAC, using Metasploit and MsfVenom on a Kali Linux machine as the attacker.
Figure 3: Demonstration network diagram
First, we should be able to establish a Meterpreter session with the target machine. One approach for initial access using Meterpreter was demonstrated on our Office Macro Attacks article.
After a session is established, we will execute getsystem to try and escalate the payload’s privileges:
Figure 4: Unsuccessfully trying to elevate meterpreter session
The command failed, meaning the privileges could not be elevated. After failing again, we pushed the session to the background and searched for UAC bypasses, which prompted many results:
Figure 5: Searching for UAC bypasses
Now we will demonstrate the use of two different bypasses. First, we used the bypassuac_injection exploit, which operates in a similar manner to the DLL injection method described above. This payload, however, uses reflective DLL injection to minimize its footprint. The payload is used to elevate our background session.
Figure 6: Configuring the “bypassuac_injection” exploit
Notice the use of set target, set session and set payload to properly configure the exploit. Now we can run it:
Figure 7: Running the “bypassuac_injection” exploit. Notice the successful operation of “getsystem”
In a very similar manner, we can use the bypassuac_fodhelper exploit. The exploit will manipulate some of fodhelper‘s registry values as described above, causing the auto-elevating process to instantiate an elevated command shell session (the exploit was attached to a new meterpreter session, session 1):
Figure 8: Configuring the “bypassuac_fodhelper” exploit
And after execution:
Figure 9: Executing “bypassuac_fodhelper”. A command shell session was opened